——by ysy

        因为差分约束是基于\(spfa\)的一种解不等式,或等式组的技巧,所以差分约束的前置知识就是\(spfa\)和对不等式的简单小变换。

​        因为差分约束只是一个技巧,所以在这里我先讲解技巧,之后再讲解例题。

建图技巧

​        我们将不等式组分为两种:\(A \le B+val\)以及\(A\ge B+val\)

​        现在讨论第一种\(A\le B+val\),我们在建图时\(B \rightarrow A\)建边,边权为\(val\),所有的不等式都像这样建边的话,我们可以在建出的图上跑最短路。

        现在为第二种\(A\ge B+val\),我们在建图时\(B \rightarrow A\)建边,边权为\(val\),所有的不等式都像这样建边的话,我们可以在建出的图上跑最长路。

​        如果我所有的式子给出的时候不是都为第一种或者第二种呢?如果不将式子的形式统一的话,就没法在建出来的图上单纯的跑最短路或者最长路。所以我们就需要将所有的式子的形式进行统一。

​        讨论完不等式了,就剩下等式。\(A=B\)我们就以这个为例。等式可以化成不等式组\(A\le B\&\& A \ge B\)。我们将这个不等式组转化成为图就是$B \rightarrow A $,边权为\(0\),同时加另一条边\(A \rightarrow B\),边权为\(0\)。这样一个等式就化为不等式的形式了。

        我在上面写的都是大于等于或者小于等于的情况,如果是大于或者小于的情况怎么办?我在这里以大于为例:\(A\gt B \rightarrow A \ge B +1\)。我们只需要将式子化成为带等于的形式就可以了。

1)[题目链接][https://www.lydsy.com/JudgeOnline/problem.php?id=3436]

​        我们看这道题目,会发现题目之中有三个限制\(X_a \ge X_b+c\)\(X_a \le X_b+c\)\(X_a=X_b\)。我们们根据这三个性质能建出来一个图。第一个条件就是$a \rightarrow b \(,边权为\)-c\(。第二个条件就是\)b \rightarrow a\(,边权为\)c\(。第三个条件就是\)a\rightarrow b \(和\)b\rightarrow a$边权都为\(0\)

​        因为我们要判断能否成立,所以我们只需要在我们建出的图上跑最短路,并且判断是否有负环,如果有则输出\(No\),否则输出\(Yes\)。因为要判断负环,所以我们很容易想到\(spfa\)

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. #define N 10010
  5. #define M 10010
  6. #define inf1 1000000000
  7. #define inf2 900000000
  8. int n,m;
  9. int head[N],nxt[M<<2],to[M<<2],val[M<<2];
  10. int dis[N],idx;bool vis[N],is;
  11. void add(int a,int b,int c)
  12. {nxt[++idx]=head[a],to[idx]=b,val[idx]=c,head[a]=idx;}
  13. void spfa(int p)
  14. {
  15.     vis[p]=true;
  16.     for(int i=head[p];i;i=nxt[i])
  17.     {
  18.         if(dis[to[i]]<=dis[p]+val[i]) continue;
  19.         dis[to[i]]=dis[p]+val[i];
  20.         if(vis[to[i]]||is) {is=true;return;}
  21.         spfa(to[i]);
  22.     }vis[p]=false;
  23. }
  24. int main()
  25. {
  26.     scanf("%d%d",&n,&m);
  27.     for(int i=1;i<=m;i++)
  28.     {
  29.         int kind,a,b,c;
  30.         scanf("%d",&kind);
  31.         if(kind==1) scanf("%d%d%d",&a,&b,&c),c=-c;
  32.         else if(kind==2) scanf("%d%d%d",&a,&b,&c),swap(a,b);
  33.         else scanf("%d%d",&a,&b),c=0,add(b,a,c);
  34.         add(a,b,c);
  35.     }
  36.     for(int i=1;i<=n;i++) dis[i]=inf1;
  37.     for(int i=1;i<=n;i++) dis[i]=0,spfa(i);
  38.     if(is) printf("No\n");
  39.     else printf("Yes");
  40. }

我有时间的话,例题会持续更下去。这是本人的见解。有问题可以评论问我。

版权声明:本文为yangsongyi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/yangsongyi/p/9840389.html