差分约束系统

差分约束系统只是对最短路算法的一种应用,没有什么新的算法,只是对于具体问题的建图方法的确定

差分约束系统解决的问题是不等式组的求解:

X1 - X2 <= 0
X1 - X5 <= -1
X2 - X5 <= 1
X3 - X1 <= 5
X4 - X1 <= 4
X4 - X3 <= -1
X5 - X3 <= -3
X5 - X4 <= -3

这就是一个不等式组,给出的不等式组只存在小于等于号,如果有个别的式子是大于等于,我们可以通过两边同时乘-1的得到统一的不等号方向的不等式组。

这个不等式组一定是无解和无数解两种情况,因为如果是存在任意一组解,{x1,x2,x3,x4,x5},我们都可以通过{x1+k,x2+k,x3+k,x4+k,x5+k}得到一个新的解。所以解的个数是无数的。

因为每个数都加k,他们任意两个数之间的差是不变的,所以对于不等式没有影响。


与最短路联系

B - A <= c     (1)

C - B <= a     (2)

C - A <= b     (3)

 如果要求C-A的最大值,可以知道max(C-A)= min(b,a+c),而这正对应了下图中C到A的最短路。 

差分约束建图技巧

1.对于一个全部都是<=号的不等式组,我们可以将每个式子转化为Xi<=Xj+W(i,j),那么就建一条边,Xj->Xi=W(i,j),然后利用最短路径解决问题,在x0定死的情况下,求得最小值

2.对于一个全部都是>=号的不等式组,我们可以将每个式子转化为Xi>=Xj+W(i,j),那么就建一条边,Xj->Xi=W(i,j),然后利用最长路径解决问题,在x0定死的情况下,求得最大值

如果dis[Xi]为inf或-inf,那么Xi为任意解

如果求最短路的过程中出现负环,那么说明该不等式组无解


来看看一道例题

【代码实现】

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include<queue>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn=1e5+5;
 7 const int INF=1e9+7;
 8 struct sd{
 9     int to,ww,next;
10 }edge[maxn<<1];
11 queue<int> que;
12 int dis[maxn],num[maxn],head[maxn],n,m,cnt;
13 bool vis[maxn];
14 void add_edge(int a,int b,int ww)
15 {
16     edge[++cnt].next=head[a];
17     edge[cnt].to=b;
18     edge[cnt].ww=ww;
19     head[a]=cnt;
20 }
21 bool spfa()
22 {
23     for(int i=1;i<=n;i++)
24     dis[i]=1,vis[i]=1,que.push(i);
25     while(!que.empty())
26     {
27         int v=que.front();que.pop();vis[v]=0;
28         for(int i=head[v];i;i=edge[i].next)
29         {
30             int to=edge[i].to;
31             if(dis[to]<dis[v]+edge[i].ww)
32             {
33                 dis[to]=dis[v]+edge[i].ww;
34                 if(!vis[to]) 
35                 {
36                     if(++num[to]>n) return false;
37                     vis[to]=1,que.push(to);
38                 }
39             }
40         }
41     }
42     return true;
43 }
44 int main()
45 {
46     int ord,a,b;
47     long long ans=0;
48     scanf("%d%d",&n,&m);
49     for(int i=1;i<=m;i++)
50     {
51         scanf("%d%d%d",&ord,&a,&b);
52         if(ord==1) add_edge(a,b,0),add_edge(b,a,0);
53         if(ord==2) {if(a==b){printf("-1");return 0;}add_edge(a,b,1);}
54         if(ord==3) add_edge(b,a,0);
55         if(ord==4) {if(a==b){printf("-1");return 0;}add_edge(b,a,1);}
56         if(ord==5) add_edge(a,b,0);
57     }
58     if(!spfa()) {printf("-1");return 0;}
59     for(int i=1;i<=n;i++) ans+=dis[i];
60     printf("%lld",ans);
61     return 0;
62 }
原文地址:https://www.cnblogs.com/genius777/p/9163103.html