差分约束

差分约束

(1) 求不等式组的可行解

步骤:

​ [1] 先将每个不等式 xi < = xj + ck 转换成一条从xj 走到 xi ,长度为ck的一条边 即表示为 离源点距离dist[i]<=dist[j]+ck

​ [2] 找一个超级源点,使得该源点一定可以遍历到所有边。

​ [3]从源点求一遍单源最短路

​ 结果1:如果存在负环,则不等式组一定无解

​ 结果2:如果没有负环,则dist[i]就是不等式组的一个可行解

(2) 如何求得最大值或最小值,最值是每个变量的最值。

结论:

①如果求的是最小值,则应该求最长路(在所有下界里,求最大值)//下界就是去为了求最小,最大值就是求能满足条件的下界中的最大值,所求即最小值。

​ 注意:如果存在正环,则无解。

②如果求的是最大值,则应该求最短路。(上界的最小值)。

​ 注意:如果存在负环,则无解。

如果求最小值,则应该是最长路,然后把所有的符号都变为>或>=

如果求最大值,则应该是最短路,然后把所有的符号都变为<或<=

例题

cWing 1169. 糖果

链接1169. 糖果 - AcWing题库

AC代码:

注意:边要加上超级源点的边,所以至少开2*m + n个边,否则会wa

#include <iostream> 
#include <cstring>
#include <stack>
using namespace std;
/*
1 a==b  a>=b+0  b>=a+0
2 a<b   b>=a+1
3 a>=b  a>=b
4 a>b   a>=b
5 a<=b  b>=a
并且建立一个超级源点
 x=0
 i>=x+1
 
 建边时: i > = j + s 则 add(j,i,s)   
 后面的指向前边的,长度为s 
*/
const int N = 1e5+5,M = 5e5+10;
typedef long long ll;
ll h[N],e[M],ne[M],idx;
ll w[M];
void add(ll a,ll b,ll c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
ll dist[N];
bool vis[N];
ll cnt[N];
stack<ll> q;
ll n,k;

bool spfa(){//在这里求最长路,并且要判断有无正环 
	memset(dist,-0x3f,sizeof dist);
	dist[0]=0;
	q.push(0);
	vis[0]=true; 
	while(q.size()){
		ll t=q.top();
		q.pop();
		vis[t]=false;
		for(ll i=h[t];i!=-1;i=ne[i]){
			ll j=e[i];
			if(dist[j]<w[i]+dist[t]){
				dist[j]=w[i]+dist[t];
				cnt[j]=cnt[t]+1;
				if(cnt[j]>=n+1) return false; 
				if(!vis[j]){
					q.push(j);
					vis[j]=true;
				}
			}
		}
	}
	return true;
}

int main(){
	scanf("%lld%lld",&n,&k);
	memset(h,-1,sizeof h); 
	ll x,a,b;
	for(ll i=0;i<k;i++){
		scanf("%lld%lld%lld",&x,&a,&b);
		if(x==1) add(b,a,0),add(a,b,0);
		else if(x==2) add(a,b,1);
		else if(x==3) add(b,a,0);
		else if(x==4) add(b,a,1); 
		else add(a,b,0); 
	} 
	for(ll i=1;i<=n;i++) add(0,i,1);
	if(!spfa()){
		printf("-1
");
	}else{
		long long ans=0;
		for(ll i=1;i<=n;i++) {
			ans+=dist[i];	
		}
		printf("%lld
",ans);
	}
}

原文地址:https://www.cnblogs.com/AC673523745/p/14829713.html