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 }

 

posted on 2017-04-18 13:41  Skype_lorenzo  阅读(818)  评论(0编辑  收藏  举报

导航