首页 > 代码库 > POJ1201-Intervals
POJ1201-Intervals
原题地址:POJ1201
知识点-差分约束
类型:给出一些形如a-b<=k的不等式(或a-b>=k或a-b<k或a-b>k等),问是否有解,或是求差的极值。
例子:b-a<=k1,c-b<=k2,c-a<=k3。将a,b,c转换为节点;k1,k2,k3转换为边权;减数指向被减数,形成一个有向图:
由题可得(b-a)+(c-b)<=k1+k2,c-a<=k1+k2。比较k1+k2与k3,其中较小者就是c-a的最大值。
根据以上解法,我们可以推出求差的最大值就是找最短路;求差的最小值就是找最长路。但是需要注意:如果要求差的最大值,那么约束条件必定要转换成a-b<=k的形式;求差的最小值则要转换成a-b>=k的形式!
那么如果一个有向图中出现负边权环,那么约束条件无解。注意:在这种情况下找最短路只能使用SPFA或是Bellman-Ford而不能用dijkstra!
例题
题目描述
You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.
Write a program that:
reads the number of intervals, their end
points and integers c1, ..., cn from the standard input,
computes the
minimal size of a set Z of integers which has at least ci common elements with
interval [ai, bi], for each i=1,2,...,n,
writes the answer to the standard
output.
题目大意:一个整数集合Z有n个区间,每个区间有3个值,ai,bi,ci代表,在区间[ai,bi]上至少有ci个整数属于集合Z,ci可以在区间内任意取不重复的点。
现在要满足所有区间的约束条件,问最少可选多少个点。
输入
The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.
第一行一个整数n,表示区间个数
以下n行描述区间,第i+1行,三个整数ai,bi,ci,由空格隔开,其中 0 <= ai <= bi <= 50000 且1 <= ci <= bi - ai+1.
输出
The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.
一行,输出满足要求序列的长度的最小值
样例输入
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1
样例输出
6
分析
题目意思是说在{ai,bi}区间和Z点集有ci个共同元素,设Si表示区间{0,i}有多少个元素,那么根据题目意思:Sbi-Sai>=ci。但是我们发现这远远不够,根本没法将所有点连接起来。所以此时我们再看一下Si的定义,易写出0<=Si-S(i-1)<=1。
现在列出三个约束条件,由于本题要求差最小值,所以约束条件是a-b>=k的形式:
Sbi-Sai>=ci
Si-S(i-1)>=0
S(i-1)-Si>=-1
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 using namespace std; 6 struct p{ 7 int to,v,nxt; 8 }edge[500001]; 9 int n,maxx,minn,cnt,a,b,c,dis[1000001],queue[10000001],heads[1000001],head,tail; 10 bool vis[1000001]={0}; 11 int addEdge(int u,int v,int val)//链式前向星 12 { 13 edge[++cnt].to=v; 14 edge[cnt].v=val; 15 edge[cnt].nxt=heads[u]; 16 heads[u]=cnt; 17 } 18 int main() 19 { 20 scanf("%d",&n); 21 maxx=-0x7fffffff,minn=0x7fffffff; 22 for(int i=1;i<=n;i++) 23 { 24 scanf("%d%d%d",&a,&b,&c); 25 addEdge(a-1,b,c); 26 minn=min(minn,a-1); 27 maxx=max(maxx,b); 28 } 29 for(int i=minn;i<=maxx;i++) 30 { 31 addEdge(i-1,i,0); 32 addEdge(i,i-1,-1); 33 } 34 for(int i=0;i<=maxx;++i) dis[i]=-10000000; 35 dis[minn]=0,queue[1]=minn,tail=1,vis[minn]=1; 36 do 37 { 38 head++; 39 int node=queue[head]; 40 for(int i=heads[node];i!=0;i=edge[i].nxt) 41 { 42 int to=edge[i].to,val=edge[i].v; 43 if(dis[to]<dis[node]+val) 44 { 45 dis[to]=dis[node]+val; 46 if(!vis[to]) 47 { 48 tail++; 49 queue[tail]=to; 50 vis[to]=1; 51 } 52 } 53 } 54 vis[node]=0; 55 }while(head!=tail); 56 printf("%d\n",dis[maxx]); 57 }
POJ1201-Intervals