基本思路:利用最短路中di≤dj+c(j指向i,边权为c,此指算法结束后)将求解三角不等式组转换为(单源)最短路问题
三角不等式(组): xi≤xj+ck 其中xi、xj是自变量,ck是常量
差分约束系统有如下功能:
源点需要满足条件:从原点出发,一定可以走到所有的边。故可设“超级源点”
超级源点:与每一个点相连的虚拟源点
步骤:
结果:
当然,求最长路亦可,需将原不等式变形为xj≥xi-ck,再将最短路不等式转化为di≥dj+ck,相当于连一条从xi走向xj、长度是-ck的边
结论:
问题1:如何转化xi≤c,其中c为常数?
解决1:以有向图为例利用超级源点x0,使xi≤x0+c,然后建立x0—>xi,长度是c
问题2:如何转化xi-xj=c,其中c为常数?
解决2:转换为xi-xj≤c和xi-xj≥c
代码:
//求最小值->求最长路 #include<iostream> #include<cstring> #include<cstdio> #include<bitset> #include<queue> #define _for(i,a,b) for (int i=(a);i<=(b);i++) using namespace std; const int N=55,M=1280; int n,m; int e[M],ne[M],h[N],w[M],idx; int d[N],cnt[N]; bitset<N> vis; inline void c_plus(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); } inline void init(){ memset(h,-1,sizeof(h)); idx=0; } inline void add(int a,int b,int c){ e[idx]=b; w[idx]=c; ne[idx]=h[a]; h[a]=idx++; } bool spfa(){ memset(d,-1,sizeof(d));//注意:最长路 d[0]=0; queue<int> q; q.push(0); vis[0]=1; while (!q.empty()){ int now=q.front(); q.pop(); vis[now]=0; for (int i=h[now];~i;i=ne[i]){ int j=e[i]; if (d[j]<d[now]+w[i]){//注意:最长路 d[j]=d[now]+w[i]; if (++cnt[j]>n+1){ return true; } if (!vis[j]){ vis[j]=1; q.push(j); } } } } return false; } int main(){ c_plus(); init(); int u,v,W,op; cin>>n>>m; while (m--){//op==1:<= op==2:>= op==3 = cin>>op>>u>>v>>W; if (op==1){ add(u,v,-W); }else if (op==2){ add(v,u,W); }else{ add(u,v,-W); add(v,u,W); } } _for(i,1,n){ add(0,i,0); } if (spfa()){ puts("NO"); }else{ _for(i,1,n){ cout<<'x'<<i<<'='<<d[i]<<endl; } } return 0; }