如果一个系统由n个变量和m个不等式组成,形如 Xj-Xi<=b*k(i,j属于[1,n],k属于[1,m] ), 这样的系统称之为差分约束系统。差分约束系统通常用于求关于一组变量的不等式组。
求解差分约束系统可以转化为图论中单源最短路问题。
Xj-Xi<=k ==> d[v]-d[u]<=w[u,v] ( 这里是我们要根据约束条件求的结果,尽量往它靠近) ==> 所以转化为图论求解 ,也就是if(d[v]-d[u] >w[u,v]) 那么 d[v]-d[u]<=w[u,v] 。 路径距离初始化 dis[i]=INF
Xj-Xi>=k ==> d[v]-d[u]>=w[u,v] ( 这里是我们要根据约束条件求的结果,尽量往它靠近) ==> 所以转化为图论求解 ,也就是if(d[v]-d[u] <w[u,v]) 那么 d[v]-d[u]>=w[u,v] 。 路径距离初始化 dis[i]=-INF
再增加一个源点s,源点到所有定点的距离为0( 添加源点的实质意义为默认另外一系列的不等式组Xi-Xo<=0),再对源点利用spfa算法。
注意几个问题:
1、当0没有被利用的时候,0作为超级源点。当0已经被利用了,将n+1(未被利用)置为超级源点。
2、对于Xj-Xi=k 可以转换为 Xj-Xi<=k Xj-Xi>=k来处理。
3、若要判断图中是否出现负环,可以利用深度优先搜索。以前利用spfa是这样的(head->****->tail),当head和tail之间所有点都遍历完了才轮得上tail这个点,这样的话我们无法判断图中有没有负环,我们可以这样改变一样遍历顺序,head->tail->***->head。 当深度优先搜索过程中下次再次遇见head(也就是head节点依然在标记栈中)时,则可判断图中含有负环,否则没有。
4、当图连通时,只需要对源点spfa一次;当图不连通时,对每个定点spfa一次。
5、对于 Xj-Xi<k or Xj-Xi>k , 差分约束系统只针对>= or <=, 所以我们还要进行巧妙转换编程大于等于小于等于。
poj 1201 ///spfa循环队列
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn=500005; 9 const int oo=0x3fffffff; 10 int dis[maxn], inque[maxn], instack[maxn],que[maxn]; 11 int n, s, t; 12 13 struct Node 14 { 15 int v, val; 16 Node (int v_, int val_) 17 { 18 v=v_, val=val_; 19 } 20 }; 21 vector<Node>vt[maxn]; 22 23 void spfa() 24 { 25 int l=0, h=0; 26 for(int i=s; i<=t; i++) 27 dis[i]=-oo, inque[i]=0; 28 que[l++]=s; 29 inque[s]=1; 30 dis[s]=0; 31 while(h<l) 32 { 33 int u=que[h++]; 34 inque[u]=0; 35 if(h==maxn) h=0; 36 for(int i=0; i<vt[u].size(); i++) 37 { 38 int v=vt[u][i].v, val=vt[u][i].val; 39 if(dis[v]<dis[u]+val) 40 { 41 dis[v]=dis[u]+val; 42 if(!inque[v]) 43 { 44 inque[v]=1; 45 que[l++]=v; 46 if(l==maxn) l=0; 47 } 48 } 49 } 50 } 51 } 52 53 int main() 54 { 55 while(cin >> n) 56 { 57 for(int i=0; i<maxn; i++) 58 vt[i].clear(); 59 t=-1, s=oo; 60 for(int i=0; i<n; i++) 61 { 62 int u, v, val; 63 scanf("%d%d%d",&u,&v,&val); 64 s=min(s,u-1); 65 t=max(t,v); 66 vt[u-1].push_back(Node(v,val)); 67 } 68 for(int i=s; i<=t; i++) 69 { 70 vt[i].push_back(Node(i+1,0)); 71 vt[i+1].push_back(Node(i,-1)); 72 vt[0].push_back(Node(i,0)); 73 } 74 spfa(); 75 printf("%d\n",dis[t]-dis[s]); 76 } 77 return 0; 78 }
poj 2983 ///spfa+深度优先搜索判断负环
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn=10005; 9 const int oo=0x3fffffff; 10 int dis[maxn], inque[maxn], instack[maxn], que[maxn]; 11 int n, m, s, t; 12 13 struct Node 14 { 15 int v, val; 16 Node (int v_, int val_) 17 { 18 v=v_, val=val_; 19 } 20 }; 21 vector<Node>vt[maxn]; 22 23 bool spfa(int u) 24 { 25 instack[u]=1; 26 for(int i=0; i<vt[u].size(); i++) 27 { 28 int v=vt[u][i].v, val=vt[u][i].val; 29 if(dis[v]>dis[u]+val) 30 { 31 dis[v]=dis[u]+val; 32 if(!instack[v]) 33 { 34 if(spfa(v)) 35 return true; 36 } 37 else 38 return true; 39 } 40 } 41 instack[u]=0; 42 return false; 43 } 44 45 int main() 46 { 47 while(cin >> n >> m) 48 { 49 for(int i=0; i<=n; i++) 50 { 51 dis[i]=oo; 52 vt[i].clear(); 53 instack[i]=0; 54 } 55 for(int i=0; i<m; i++) 56 { 57 char ch[2]; 58 int u, v, val; 59 scanf("%s",ch); 60 if(ch[0]=='P') 61 { 62 scanf("%d%d%d",&u,&v,&val); 63 vt[u].push_back(Node(v,val)); 64 vt[v].push_back(Node(u,-val)); 65 } 66 else 67 { 68 scanf("%d%d",&u,&v); 69 vt[v].push_back(Node(u,-1)); 70 } 71 } 72 for(int i=0; i<=n; i++) 73 vt[0].push_back(Node(i,0)); 74 dis[0]=0; 75 bool ok=spfa(0); 76 if(ok) 77 puts("Unreliable"); 78 else puts("Reliable"); 79 } 80 return 0; 81 }
hdu 3666
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <cmath> 6 #include <algorithm> 7 using namespace std; 8 9 const int maxn=1024; 10 const double oo=0x3fffffff; 11 double dis[maxn]; 12 int instack[maxn]; 13 int n, m; 14 double L, U; 15 16 struct Node 17 { 18 int v; 19 double val; 20 Node(int v_, double val_) 21 { 22 v=v_, val=val_; 23 } 24 }; 25 vector<Node>vt[maxn]; 26 27 bool spfa(int u) 28 { 29 instack[u]=1; 30 for(int i=0; i<vt[u].size(); i++) 31 { 32 int v=vt[u][i].v; 33 double val=vt[u][i].val; 34 if(dis[v]<dis[u]+val) 35 { 36 dis[v]=dis[u]+val; 37 if(!instack[v]) 38 { 39 if(spfa(v)) 40 return true; 41 } 42 else 43 return true; 44 } 45 } 46 instack[u]=0; 47 return false; 48 } 49 50 bool judge() 51 { 52 for(int i=1; i<=n+m; i++) 53 { 54 fill(dis,dis+n+m+1,-oo); 55 fill(instack,instack+n+m+1,0); 56 if(spfa(i)) 57 return true; 58 } 59 return false; 60 } 61 62 int main() 63 { 64 while(cin >> n >> m >> L >> U) 65 { 66 for(int i=0; i<=n+m+1; i++) 67 vt[i].clear(); 68 for(int i=1; i<=n; i++) 69 for(int j=1; j<=m; j++) 70 { 71 double val; 72 scanf("%lf",&val); 73 vt[j+n].push_back(Node(i,log(L)-log(val))); 74 vt[i].push_back(Node(j+n,-(log(U)-log(val)))); 75 } 76 bool ok=judge(); 77 if(ok) 78 puts("NO"); 79 else puts("YES"); 80 } 81 return 0; 82 }
poj 1364
#include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <algorithm> using namespace std; const int maxn=10024; const double oo=0x3fffffff; double dis[maxn]; int instack[maxn]; int n, m, t; struct Node { int v; double val; Node(int v_, double val_) { v=v_, val=val_; } }; vector<Node>vt[maxn]; bool spfa(int u) { instack[u]=1; for(int i=0; i<vt[u].size(); i++) { int v=vt[u][i].v; double val=vt[u][i].val; if(dis[v]<dis[u]+val) { dis[v]=dis[u]+val; if(!instack[v]) { if(spfa(v)) return true; } else return true; } } instack[u]=0; return false; } int main() { int u, v, val; char ch[5]; while(cin >> n, n) { cin >> m; for(int i=0; i<maxn; i++) vt[i].clear(); t=-1; for(int i=0; i<m; i++) { scanf("%d%d%s%d",&u,&v,ch,&val); t=max(t,u+v); if(ch[0]=='g') { vt[u-1].push_back(Node(u+v,val+1)); } else { vt[u+v].push_back(Node(u-1,-val+1)); } } for(int i=0; i<=t; i++) ///注意超级源点的建立 vt[t+1].push_back(Node(i,0)); for(int i=0; i<=t; i++) dis[i]=-oo, instack[i]=0; dis[t+1]=0; bool ok=spfa(t+1); if(ok) puts("successful conspiracy"); else puts("lamentable kingdom"); } return 0; }