poj 1201 Intervals(差分约束)

做的第一道差分约束的题目,思考了一天,终于把差分约束弄懂了O(∩_∩)O哈哈~

题意(略坑):三元组{ai,bi,ci},表示区间[ai,bi]上至少要有ci个数字相同,其实就是说,在区间[0,50000]上,每一个三元组表示[ai,bi]之间至少要标记ci个数字,问至少要标记多少个数字。

在学习差分约束的童鞋,建议看一下:09年姜碧野的《SPFA算法的优化及应用》,06年冯威的《浅析差分约束系统》,不过后者看起来较难搞懂,也可以看http://ycool.com/post/m2uybbf 写的很不错。

这里写一下我自己的一点心得:

1、差分约束求的是什么?

  这里分为两种:求值,判环。

  求值:如这道题所示,最终求的是整个区间上被标记点的最小数量,也就是从起点到终点的最小值,不需考虑判环的情况。更广泛的讲,它可以求解不等式的一组解。

  判环:poj 1364判断存不存在,即判正负环。

2、差分约束中的松弛操作

  举个最短路的例子,1->2 c=3,1->3 c=1,3->2 c=1,即以1为起点,d[2]>d[3]+w(3,2),可以进行松弛。而三条边本身表示的是:a(2)-a(1)<=3,a(3)-a(1)<=1,a(2)-a(3)<=1,我们是从d[]=INF一路更新过来的,用1->3->2这条边更新1->2,实际上表示的是后两个不等式之和a(2)-a(1)<=2比第一个不等式的约束条件更强。

3、最长路与最短路的区别

  两者不仅是在三角不等式的表现形式上不同,具体求解的值也不同。

  首先要明确,需要额外的一个限定条件:一般为加入源点s,并建立权值为0的边。对于一个不等式组来说,只要有一组解,那么同时加上定值k,仍然满足约束条件。

  最短路:d[v]<d[u]+w(u,v),d[i]初始化为INF,而求解出来的是不等式的最大值。何为最大值?若确定其中一个的值,并非能得到每个数的定值,因为是不等式,所以每个值有其取值范围。这里的最大值就是在源点s的限定条件内,所能够取值的上界。仔细思考,这里的最短路只是满足不等式组条件所找到的解,由于最短路是由大到小做松弛操作,找到的最短路即为“最大”。

  最长路:d[v]>d[u]+w(u,v),d[i]初始化为-INF,解释同上。这道题目求的是最小值,自然就只能由最长路求解。

4、关于点的数量

  如题目所示{ai,bi,ci},[ai,bi]上至少标记ci个点,可以转化为:s(bi)-s(ai-1)>=ci,注意是(ai-1)而非(ai),由于减1的关系,总点数+1。

  在判环过程中,SPFA的判定条件为入队n次,其实质是最短路最长经过(n-1)条边,所以入队n次队列仍不为空,即可以判定存在正负环。当点的总数+1,对应的SPFA判环的条件也就变更为cnt[]>n。

5、关于图的连通性

  无论是求值,还是判环,原图不构成强连通的前提下都是不能搜索到每一个点的,所以才出现设立一个源点s的方法。事实上,能够到达各个点,更加实用的是在SPFA初始化时,就把所有点加入队列,并把d[i]全部初始化为0。不仅仅是解决了连通的问题,更是避免了错误——加上一个源点s,使总点数为(n+2),SPFA的判环条件必须为cnt[]>(n+1),这是很容易忽视的问题。

  这道题由于存在所谓的隐藏条件0<=s(i)-s(i-1)<=1,据此建图已经能够实现图上的连通。

6、不等式的变形

  差分约束解决的是>=和<=的问题,若题目给出的是>k(或<k),需要变形。比如若k是整数,>k等价于>=k+1。

7、无穷解,无解。

  http://www.cnblogs.com/zstu-abc/archive/2013/08/18.html

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #include<algorithm>
 5 #define rep(i,a,b) for(int i=a;i<=b;i++)
 6 #define clr(a,m) memset(a,m,sizeof(a))
 7 using namespace std;
 8 
 9 const int MAXN=55555;
10 const int INF =MAXN;
11 
12 struct Edge{
13     int v,c,next;
14     Edge(){}
15     Edge(int _v,int _c,int _next):v(_v),c(_c),next(_next){}
16 }edge[MAXN<<2];
17 
18 int head[MAXN],tol;
19 int d[MAXN],inq[MAXN];
20 
21 void init()
22 {
23     tol=0;
24     clr(head,-1);
25 }
26 
27 void add(int u,int v,int c)
28 {
29     edge[tol]=Edge(v,c,head[u]);
30     head[u]=tol++;
31 }
32 
33 void SPFA(int down,int up)
34 {
35     queue<int>q;
36     clr(inq,0);
37     rep(i,down,up)
38         if(i==down)d[i]=0;
39         else d[i]=-INF;
40     q.push(down);
41     inq[down]=true;
42     while(!q.empty())
43     {
44         int u=q.front();q.pop();
45         inq[u]=false;
46         for(int i=head[u];i!=-1;i=edge[i].next)
47         {
48             int v=edge[i].v;
49             int c=edge[i].c;
50             if(d[v]<d[u]+c){
51                 d[v]=d[u]+c;
52                 if(!inq[v]){
53                     q.push(v);
54                     inq[v]=true;
55                 }
56             }
57         }
58     }
59 }
60 
61 int main()
62 {
63     int n,up=0,down=MAXN;
64     int u,v,c;
65     scanf("%d",&n);
66 
67     init();
68     rep(i,1,n){
69         scanf("%d%d%d",&u,&v,&c);
70         add(--u,v,c);
71         up=max(up,v);
72         down=min(down,u);
73     }
74     rep(i,down,up){
75         add(i-1,i,0);
76         add(i,i-1,-1);
77     }
78     SPFA(down,up);
79 
80     printf("%d\n",d[up]);
81     return 0;
82 }
View Code

 

posted @ 2013-08-23 13:07  Thousand Sunny  阅读(417)  评论(0编辑  收藏  举报