• 差分约束系统


    训练地址

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


    第二:
    ①:对于差分不等式,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; // 找到最矮的树和最高的树的位置
  • 相关阅读:
    Freemarker进行非空处理
    Freemarker导出带多个不重复图片的word
    Freemarker导出带图片的word
    怎样在Android本地视频播放器开发
    详细解说九宫图比较常用的多控件布局
    POJ 3189 Steady Cow Assignment【网络流】
    C++获取文件大小常用技巧
    operation is executing and cannot be enqueued
    Android 异步链式调用设计
    LINUX编程学习笔记(十三) 遍历目录的两种方法
  • 原文地址:https://www.cnblogs.com/khan724/p/4485810.html
Copyright © 2020-2023  润新知