差分约束系统

157 阅读1分钟

算法思想

对于一系列形如abca-b\leq c的不等式组,要求得是否有解或者解为多少,可以利用求最短路的方法。
将原式变形后得到ab+ca\leq b+c,类比单源最短路中的对于边u->v(w),dis[v]dis[u]+wdis[v]\leq dis[u]+w,可以连一条b到a的带权边,再在整张图上跑单源最短路。答案就是dis[v]。

例题

小 K 的农场

#include <bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
const int N=5E3+10,M=1E4+10;
int n,m,tot;
int dis[N];
string ans;
struct Edge{
	int u,v,w;
}e[M];
inline int read()
{
	int ret=0;char ch=getchar();
	while(ch<'0' || ch>'9')
		ch=getchar();
	while(ch>='0' && ch<='9')
	{
		ret=ret*10+ch-'0';
		ch=getchar();
	}
	return ret;	
}
void add_edge(int u,int v,int w)
{
	e[++tot].u=u;e[tot].v=v;e[tot].w=w;
}
int Bellman_Ford()
{
	rep(i,1,n)
	{
		int flag=0;
		rep(j,1,tot)
		{
			int u=e[j].u,v=e[j].v,w=e[j].w;
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				flag=1;
			}
		}
		if(i==n && flag)
			return 0;
	}
	return 1;
}
int main()
{
	n=read();m=read();
	int a,b,c,op;
	rep(i,1,m)
	{
		op=read();
		switch(op)
		{
			case 1:a=read();b=read();c=read();add_edge(a,b,-c);break;
			case 2:a=read();b=read();c=read();add_edge(b,a,c);break;
			case 3:a=read();b=read();add_edge(a,b,0);add_edge(b,a,0);break;
		}
	}
	int flag=Bellman_Ford();
	if(flag)
		ans="Yes";
	else 
		ans="No";
	cout<<ans<<endl;
}