差分约束系统
真的已经很久没有写博客了。。博客还是挺有用的,让自己复习的时候随时能理解,比如去年的欧拉路径(
1.是什么
“如果一个系统由n个变量和m个约束条件组成,其中每个约束条件形如Xj-Xi<=bk(i,j∈[1,n],k∈[1,m]),则称其为差分约束系统(system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法。”
2.怎么思考
比如有这样的不等式组:
x1-x2<=y1
x3-x2<=y2
x3-x1<=y3
我们可以转化成:
x1<=x2+y1
x3<=x2+y2
x3<=x1+y3
可以发现这个东西很像单源最短路里面松弛边的操作,所以我们可以把求不等式的解转化成用spfa求最短路(用spfa是因为有负权边)
而当该图里面有负环时,不等式组无解
3.大概流程
1.建图
用链式前向星就可以,但要注意add函数里面参数的位置
x1-x2<=y1——add(x2,x1,y1)//这个是因为x1<=x2+y1 x1为终点,x2为出发点,y为路的长度
x1-x2>=y1——x2-x1<=-y1——add(x1,x2,-y1)
x1>x2——x1-x2>0——x1-x2>=1——add(x1,x2,-1)[当解一定为整数时]
x1<x2——x1-x2<0——x1-x2<=-1——add(x2,x1,-1)[当解一定为整数时]
x1=x2——add(x1,x2,0)add(x2,x1,0)
2.因为根据不等式组建的图可能是不连通的,所以我们建立一个0号结点,当作跑最短路时的起点
add(每个结点,0,0)
add(0,每个结点,0)
3.跑spfa,记得判负环的时候>n+1,因为还有一个0号结点
4.代码
#include<iostream> #include<cstdio> #include<queue> #include<cstring> using namespace std; const long long N=1e6+10; queue<int> q; int n,m,a,b,c; int dis[N],ver[N],book[N]; int tot=0,head[N],nxt[N],v[N],w[N]; void add(int x,int y,int z){ tot++; v[tot]=y; w[tot]=z; nxt[tot]=head[x]; head[x]=tot; } void spfa(int x){ memset(dis,0x3f3f3f3f,sizeof(dis)); dis[x]=0; ver[x]=1; book[x]++; q.push(x); while(!q.empty()){ int h=q.front(); q.pop(); ver[h]=0; for(int i=head[h];i;i=nxt[i]){ if(dis[v[i]]>dis[h]+w[i]){ dis[v[i]]=dis[h]+w[i]; book[v[i]]=book[h]+1; if(book[v[i]]>n+1){ printf("NO\n"); exit(0); } if(ver[v[i]]==0){ ver[v[i]]=1; q.push(v[i]); } } } } } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ scanf("%d%d%d",&a,&b,&c); add(b,a,c); } for(int i=1;i<=n;i++){ add(0,i,1); } spfa(0); for(int i=1;i<=n;i++){ printf("%d ",dis[i]); } return 0; }
欢迎指错共同进步