[POJ 1201] Intervals 差分约束系统
2017-10-12 16:43
381 查看
题目传送门:【POJ 1201】
题目大意:给定一个长度为 n 的序列(1 ≤ n ≤ 50000),序列中所有数字都为非负数且不相同。
题目将会以一些三元组 [a,b,c] 对这个数列进行描述,表示第 i 个序列中数值在 [ai,bi] 之间的数字至少有 ci 个。
询问使得所有条件都成立的序列长度最短是多少。(0 ≤ ai ≤ bi ≤ 50000,1 ≤ ci ≤ bi - ai + 1)
注意,输入中仅包含 n 和之后 n 个区间的信息。
题目分析:
这道题有很多种做法。不过对于差分约束系统来说,应该是一道裸题了。
我们设 Si 表示 0-i 中必须要选的数的个数;那么,根据题目信息,我们可以将所有的三元组 [ai , bi , ci] 转化为一系列的不等式:Sbi- Sai−1 ≥ ci 。然后,对于这样的不等式,我们对所有的 ai-1 号点到 bi 号点连一条权值为 ci 的单向边。
题目中还有两个隐含条件:Si−1 ≤ Si ≤ Si−1+1;对于这样的条件,我们对 i-1 号点到 i 号点连一条权值为 0 的单向边,然后从 i 号点到 i-1 号点连一条权值为 -1 的边(这样可以保证不会走成一个环,同时也可以绕回去)。然后,跑一遍最长路即可。
至于要怎么跑最长路……其实把 dis 数组初始化为一个很小的数,然后判断条件改成 dis[u] + len > dis[v] 就行辣
下面附上代码:
[cpp] view plain copy print?#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int MX=50005;
struct Edge{
int to,len,next;
}edge[MX*4];
int n,m,head[MX],now=0,dis[MX],cnt=0;
bool inq[MX];
queue<int> q;
inline void adde(int u,int v,int len){
edge[++now].to=v;
edge[now].len=len;
edge[now].next=head[u];
head[u]=now;
}
void bfs(int s){
q.push(s);
dis[s]=0;
inq[s]=true;
while (!q.empty()){
int u=q.front();
q.pop();
inq[u]=false;
for (int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if (dis[u]+edge[i].len>dis[v]){ //求最长路
dis[v]=dis[u]+edge[i].len;
if (!inq[v]){
inq[v]=true;
q.push(v);
}
}
}
}
}
int main(){
memset(dis,0x9f,sizeof(dis));
int a,b,v;
scanf(”%d”,&m);
for (int i=1;i<=m;i++){
scanf(”%d%d%d”,&a,&b,&v); //这里的处理(b++)使得起始点变为 1,防止溢出
b++;
adde(a,b,v);
}
for (int i=1;i<=50000;i++){ //区间覆盖的最大值为 50000,所以只需要建到 50000
adde(i,i+1,0);
adde(i+1,i,(-1));
}
bfs(1);
printf(”%d”,dis[50001]);
return 0;
}
题目大意:给定一个长度为 n 的序列(1 ≤ n ≤ 50000),序列中所有数字都为非负数且不相同。
题目将会以一些三元组 [a,b,c] 对这个数列进行描述,表示第 i 个序列中数值在 [ai,bi] 之间的数字至少有 ci 个。
询问使得所有条件都成立的序列长度最短是多少。(0 ≤ ai ≤ bi ≤ 50000,1 ≤ ci ≤ bi - ai + 1)
注意,输入中仅包含 n 和之后 n 个区间的信息。
题目分析:
这道题有很多种做法。不过对于差分约束系统来说,应该是一道裸题了。
我们设 Si 表示 0-i 中必须要选的数的个数;那么,根据题目信息,我们可以将所有的三元组 [ai , bi , ci] 转化为一系列的不等式:Sbi- Sai−1 ≥ ci 。然后,对于这样的不等式,我们对所有的 ai-1 号点到 bi 号点连一条权值为 ci 的单向边。
题目中还有两个隐含条件:Si−1 ≤ Si ≤ Si−1+1;对于这样的条件,我们对 i-1 号点到 i 号点连一条权值为 0 的单向边,然后从 i 号点到 i-1 号点连一条权值为 -1 的边(这样可以保证不会走成一个环,同时也可以绕回去)。然后,跑一遍最长路即可。
至于要怎么跑最长路……其实把 dis 数组初始化为一个很小的数,然后判断条件改成 dis[u] + len > dis[v] 就行辣
下面附上代码:
[cpp] view plain copy print?#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long LL;
const int MX=50005;
struct Edge{
int to,len,next;
}edge[MX*4];
int n,m,head[MX],now=0,dis[MX],cnt=0;
bool inq[MX];
queue<int> q;
inline void adde(int u,int v,int len){
edge[++now].to=v;
edge[now].len=len;
edge[now].next=head[u];
head[u]=now;
}
void bfs(int s){
q.push(s);
dis[s]=0;
inq[s]=true;
while (!q.empty()){
int u=q.front();
q.pop();
inq[u]=false;
for (int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
if (dis[u]+edge[i].len>dis[v]){ //求最长路
dis[v]=dis[u]+edge[i].len;
if (!inq[v]){
inq[v]=true;
q.push(v);
}
}
}
}
}
int main(){
memset(dis,0x9f,sizeof(dis));
int a,b,v;
scanf(”%d”,&m);
for (int i=1;i<=m;i++){
scanf(”%d%d%d”,&a,&b,&v); //这里的处理(b++)使得起始点变为 1,防止溢出
b++;
adde(a,b,v);
}
for (int i=1;i<=50000;i++){ //区间覆盖的最大值为 50000,所以只需要建到 50000
adde(i,i+1,0);
adde(i+1,i,(-1));
}
bfs(1);
printf(”%d”,dis[50001]);
return 0;
}
相关文章推荐
- POJ 1201 Intervals(差分约束系统)
- POJ 1201 Intervals 差分约束系统
- poj 1201 Intervals(差分约束系统)
- 【差分约束系统】POJ 1201--Intervals
- POJ1201 Intervals[差分约束系统]
- POJ 1201 Intervals (差分约束系统, 贪心+线段树)
- 【POJ 1201】 Intervals(差分约束系统)
- ZOJ 1508 poj 1201 Intervals 差分约束系统
- POJ 1201 Intervals (差分约束系统)
- POJ 1201 Intervals <差分约束系统 + SPFA / 贪心 + 树状数组>
- POJ 1201-Intervals(差分约束系统)
- POJ 1201 Intervals 差分约束系统
- POJ 1201 Intervals 差分约束系统
- POJ 1201-Intervals(差分约束系统)
- POJ -- 1201--Intervals (差分约束系统)
- POJ 1201 Intervals(差分约束系统)
- POJ 1201 Intervals(差分约束系统)
- 差分约束系统_bellman_ford_poj 1201 Intervals
- POJ 1201 && HDU 1384 Intervals(差分约束系统)
- poj 1201 Intervals(差分约束系统)(中等)