差分約束系統


差分約束系統只是對最短路算法的一種應用,沒有什么新的算法,只是對於具體問題的建圖方法的確定

差分約束系統解決的問題是不等式組的求解:

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 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM