差分约束系统

 

 

训练地址

 

先总结下:
第一:
感觉难点在于建图


第二:
①:对于差分不等式,a - b <= c ,建一条 b 到 a 的权值为 c 的边,求的是最短路,得到的是最大值
②:对于不等式 a - b >= c ,建一条 b 到 a 的权值为 c 的边,求的是最长路,得到的是最小值
③:存在负环的话是无解
④:求不出最短路(dist[ ]没有得到更新)的话是任意解


第三:
一种建图方法:
设x[i]是第i位置(或时刻)的值(跟所求值的属性一样),那么把x[i]看成数列,前n项和为s[n],则x[i] = s[i] - s[i-1];
那么这样就可以最起码建立起类似这样的一个关系:0 <= s[i] - s[i-1] <= 1;
其他关系就要去题目探索了

以上转载于这里

 

 

第一题意:

   输入n个学生和m个比较关系:a,b,c表示学生a认为学生b得到的糖果不能比他多c。问你学生1和学生n之间糖果数量最大是多少?

  分析:直接按b-a<=c来建图即可。

第二题意:

  给你一个序列的起点 Si 和序列的长度ni,以及他们的区间和与给定的数 ki 的大小关系,然后问你是否存在这样的关系?

  分析:(1) 给的不是序列的起点和终点,而是起点和序列长度,所以区间为 [Si, Si+n],这里容易出错。

     (2) 要把 > 和 < 关系,通过 Ki-1 变为 <= 和 >= 的关系。

        (3) Si +Si+1+.....+ Si+n  < ki  可转化为 Sum(i+n) - Sum(i-1) < Ki 从而满足差分约束系统。

     (4) 题目中没有指明源点,故设置n+1为超级源点,从超级源点跑spfa即可。

 

 1 tot = 0;
 2 _Clr(head, -1);
 3 while(m--)
 4 {
 5     scanf("%d%d%s%d", &a, &b, p, &c);
 6     if(p[0]=='g')
 7         Add_edge(a+b, a-1, -c-1);
 8     else
 9         Add_edge(a-1, a+b, c-1);
10 }
11 int S = n+1;
12 for(int i=0; i<=n; i++)
13     Add_edge(S, i, 0);

 

 

 

第三题意:

  给你n个整数区间 [a,b]。让你找一个最小的集合Z,使得Z与每个区间的交集都至少有两个不同的元素。问你Z的大小最小是多少?

  分析: 用Si表示区间[0, i]的整数个数,由题可知,任一个区间 [a, b] 最少应包含两个元素;即 Sb-Sa-1>=2 。

     还有一个隐含条件:因为是整数区间,那么任一相邻的两个区间Si和Si-1满足关系:0 <= Si-Si-1 <= 1。

     还要添加一个源点,让你求最小值,所以求最长路即可。

 1 tot = 0;
 2 _Clr(head, -1);
 3 while(m--)
 4 {
 5     scanf("%d%d", &a, &b);
 6     Add_edge(a, b+1, 2);
 7     n = max(n, b+1);
 8 }
 9 S = n+3;   // 源点S=n+2也是一样的
10 for(int i=0; i<n; i++)
11 {
12     Add_edge(i+1, i, -1);
13     Add_edge(i, i+1, 0);
14     Add_edge(S, i, 0);
15 }

 

第四题意:

  和上提基本一样,就是交集不再为2,而是 ci,起点和终点是整个区间的最左边的点和最右边的点。

 1 tot = 0;
 2 _Clr(head, -1);
 3 for(int i=0; i<n; i++)
 4 {
 5     scanf("%d%d%d", &a, &b, &c);
 6     Add_edge(a, b+1, c);
 7     st = min(a, st);
 8     ed = max(b+1, ed);
 9 }
10 for(int i=st; i<=ed; i++)
11 {
12     Add_edge(i, i+1, 0);
13     Add_edge(i+1, i, -1);
14 }

第五题意:

  有n头奶牛排成一队,他们都喜欢尽量和关系好的靠的进些,和关系坏的离的远些(允许多个奶牛站在同一个点)。ml个友好关系 a,b,d表示a,b之间最远只能隔d; 和md个反感关系 a,b,d表示a,b之间至少要相隔d。问你奶牛1和奶牛n之间的最大距离是多少?如果无法排成一队输出-1,如果他们之间可以无限大则输出-2。

  分析:用 Si 表示 i 和 1 之间的距离,那么建图关系已经很明显了,不过,还有一个比较隐含的条件:Si-Si-1>=0。因为相邻两个之间可以站同一个位置。

 1 tot = 0;
 2 _Clr(head, -1);
 3 for(int i=0; i<ml; i++)
 4 {
 5     scanf("%d%d%d", &a, &b, &c);
 6     Add_edge(a, b, c);
 7 }
 8 for(int i=0; i<md; i++)
 9 {
10     scanf("%d%d%d", &a, &b, &c);
11     Add_edge(b, a, -c);
12 }
13 for(int i=1; i<=n; i++)   // 不过,去掉这个隐含条件也能AC。唉.....
14     Add_edge(i+1, i, 0)

第六题意:

还不会做,先留着。。。。。

 

第七题意:

  n个岗哨,m个信息。信息有两个格式:P A B X 表示岗哨 A 在岗哨 B 北边 X 光年处;V A B 表示岗哨 A 在岗哨 B 北边至少 1 光年处。然后,让你确定这m条信息是否是可靠的或不可靠的?

  分析: 用 S(i) 表示岗哨 i 在岗哨 S 北边的距离。那么对于P A B X就有 S(A) - S(B) = X;可以转化为:S(A)-S(b)>=X && S(A)-S(B)<=X 来建图。

      S 是自己设立的源点。

 1 tot = 0;
 2 _Clr(head, -1);
 3 while(m--)
 4 {
 5     scanf(" %c%d%d", &p, &a, &b);
 6     if(p=='P')
 7     {
 8         scanf("%d", &c);
 9         Add_edge(b, a, c);
10         Add_edge(a, b, -c);
11     }
12     else
13         Add_edge(a, b, -1);
14 }
15 for(int i=1; i<=n; i++)
16     Add_edge(0, i, 0);

第八题意:

  有个忍者在一排树上联系跳跃,他严格的按照树的高度从矮到高的顺序跳,但是他跳的距离有个限制 D。问你最矮的树和最高的树之间的最长距离是多少?

  分析:有一个需要的注意就是他是从左往右跳的还是从右往左跳的?还有一个隐含限制条件:每棵树都是在一个整数点,也就是两颗树之间距离最近为1,即 Si-Si-1>=1。

 1 tot = 0;
 2 _Clr(head, -1);
 3 for(int i=1; i<=n; i++)
 4 {
 5     scanf("%d", &tree[i].h);
 6     tree[i].id = i;
 7 }
 8 sort(tree+1, tree+n+1);
 9 for(int i=1; i<n; i++)
10 {
11     int u = tree[i].id;
12     int v = tree[i+1].id;
13     if(u > v)    // 从左往右跳
14         Add_edge(v, u, d);
15     else     // 反之。
16         Add_edge(u, v, d);
17     Add_edge(i+1, i, -1);    // 相邻两课树不能在同一个位置。
18 }
19 int st=tree[1].id, ed=tree[n].id; // 找到最矮的树和最高的树的位置

 

posted @ 2015-05-07 19:24  无道圣君  阅读(291)  评论(0编辑  收藏  举报