【图论】差分约束系统

这篇博客介绍了差分约束系统如何转化为图论中的单源最短路径问题。通过举例说明了如何将不等式组转换为图的边,并利用SPFA或Bellman-Ford算法求解最短路径,从而找到差分约束系统的可行解。同时,文章提到了负环的存在意味着无解,并给出了判断负环的条件。最后,提供了相关算法的代码实现。
摘要由CSDN通过智能技术生成

差分约束系统

芜湖~ 图论和不等式的梦幻联动

如果一个系统由 n n n个变量和 m m m个约束条件组成,形成 m m m个形如 a i − a j ≤ k ai-aj≤k aiajk 的不等式( i , j ∈ [ 1 , n ] i,j∈[1,n] i,j[1,n],k为常数),则称其为差分约束系统 (system of difference constraints)。亦即,差分约束系统是求解关于一组变量的特殊不等式组的方法

求解差分约束系统,可以转化成图论的单源最短路径问题

例: 对于一组由4个变量4个约束条件构成的不等式
{ x 3 − x 1 ≤ 2 x 4 − x 3 ≤ − 1 x 3 − x 2 ≤ − 3 x 2 − x 4 ≤ 5 \begin{cases} x3-x1≤2\\ x4-x3≤-1\\ x3-x2≤-3\\ x2-x4≤5 \end{cases} x3x12x4x31x3x23x2x45

求一组可行解

首先我们易得,当此组不等式有解时,必然存在无数组可行解否则无解
假设我们已知一组可行解 { x 1 , x 2 , . . . , x n x1,x2,...,xn x1,x2,...,xn},则 { x 1 + k , x 2 + k , . . . , x n + k x1+k,x2+k,...,xn+k x1+k,x2+k,...,xn+k}, …, { x 1 + m k , x 2 + m k , . . . , x n + m k x1+mk,x2+mk,...,xn+mk x1+mk,x2+mk,...,xn+mk} ( k , m ∈ R ) (k,m∈R) (k,mR) 均为可行解

问题转化

对于不等式组:
{ B − A ≤ c . . . ① C − B ≤ a . . . ② C − A ≤ b . . . ③ \begin{cases} B - A ≤ c...①\\ C - B ≤ a...②\\ C - A ≤ b...③ \end{cases} BAc...CBa...CAb...
① + ② 得
C − A ≤ a + c . . . ④ C-A ≤ a+c...④ CAa+c...

由③④ 根据不等式的基本性质
可得 C − A ≤ m i n ( a + c , b ) C-A≤min(a+c, b) CAmin(a+c,b)
m a x ( C − A ) = m i n ( a + c , b ) max(C-A)=min(a+c,b) max(CA)=min(a+c,b)

可以发现该不等式正好对应下图的最短路问题
在这里插入图片描述
从公式入手,我们比较一下这两个问题涉及到的三角不等式的相似性
C − A ≤ m i n ( a + c , b ) C-A≤min(a+c, b) CAmin(a+c,b)
d i s A , C ≤ d i s A , B + w a , c dis_{A,C}≤dis_{A,B}+w_{a,c} disA,CdisA,B+wa,c
是不是一模一样

因此对于不等式 x v − x u ≤ w x_v-x_u≤w xvxuw 我们可以建立一条由节点 u u u指向节点 v v v边权为 w w w的边

//u v w
  1 3 2
  3 4 -1
  2 3 -3
  4 2 5

建图
请添加图片描述

对于非连通图,例如本张图,在解决差分约束问题时,需要增加一个超级源点0建立由0点到其他各点边权为0的n条边,将问题转换为单源最短路。
对于连通图,(本身就可以当做单源最短路问题),我们可以以任意一点为起点,记录该点到其他点的最短路,dis[]则为一组可行解。

请添加图片描述
如此一来,我们记录源点到各个点的最短路径:
d i s [ 1 ] = 0 , d i s [ 2 ] = 0 , d i s [ 3 ] = − 1 , d i s [ 4 ] = − 4 dis[1]=0 ,dis[2]=0,dis[3]=-1,dis[4]=-4 dis[1]=0,dis[2]=0,dis[3]=1,dis[4]=4
其所构成的一组解为:
{ x 1 = 0 , x 2 = 0 , x 3 = − 1 , x 4 = − 4 x_1=0,x_2=0,x_3=-1,x_4=-4 x1=0,x2=0,x3=1,x4=4} 。

因此我们只需建图,跑一遍最短路即可。求解最短路可以使用spfabellman-ford算法,由于存在负权边,不能使用dijkstra

特判无解

当图中存在负权环时,源点到某点的最短路径变为负无穷,显然不成立,则不等式组无解。
因此在跑最短路的过程中我们需要判负环。即在spfa中,当某个节点被入队n次,则存在负环
P3358负环模板题 洛谷传送门
重点强调判负环的时候是在入队之后判 不是在松弛操作的时候判!!!!!!

if(!vis[v]){
	cnt[v]++; //点v入队次数
	vis[v]=1; //访问标记 注意在取队首的时候要释放标记!!!!
	q.push(v); //入队
	if(cnt[v]>=n) { //判负环
		printf("NO");
		return ;
	}
}

代码

P5960差分约束算法模板题 洛谷传送门

题目描述
给出一组包含 m m m 个不等式,有 n n n 个未知数的形如:
{ x c 1 − x c 1 ′ ≤ y 1 x c 2 − x c 2 ′ ≤ y 2 . . . x c m − x c m ′ ≤ y m \begin{cases} x_{c1}-x_{c1'}\le y_1& \\ x_{c2}-x_{c2'}\le y_2 & \\ ...\\ x_{cm}-x_{cm'}\le y_m \end{cases} xc1xc1y1xc2xc2y2...xcmxcmym
的不等式组,求任意一组满足这个不等式组的解。

输入格式
第一行为两个正整数 n , m n,m n,m,代表未知数的数量和不等式的数量。
接下来 m m m 行,每行包含三个整数 c , c ′ , y c,c',y c,c,y, 代表一个不等式 x c − x c ′ ≤ y x_c-x_c'\le y xcxcy

输出格式
一行, n n n 个数,表示 x 1 , x 2 , . . . , x n x_1,x_2,...,x_n x1,x2,...,xn的一组可行解,如果有多组解,请输出任意一组,无解请输出 NO

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define inf 0x3f3f3f3f
#define maxn 6000
#define maxm 11000
using namespace std;
int n,m,ct,flag;
int head[maxn],vis[maxn],dis[maxn],cnt[maxn];
struct node{
	int to,next,w;
}e[maxm];
//没啥好解释的
void add(int u,int v,int w){
	ct++;
	e[ct].w =w;
	e[ct].to =v;
	e[ct].next =head[u];
	head[u]=ct;
}

queue<int>q;
void spfa(int s){
	for(int i=1;i<=n;i++){
		dis[i]=inf;
	}
	q.push(s); 
	vis[s]=1; dis[s]=0;
	while(!q.empty() ){
		int t=q.front() ; q.pop(); vis[t]=0;//注意释放标记啊啊啊
		for(int i=head[t];i!=-1;i=e[i].next ){
			int v=e[i].to;
			if(dis[v]>dis[t]+e[i].w){
				dis[v]=dis[t]+e[i].w; // 松弛操作
				if(!vis[v]){
					cnt[v]++;
					vis[v]=1;
					q.push(v); 
					if(cnt[v]>=n) { //判负环
						printf("NO");
						flag=1;
						return ;
					}
				}
			}
		}
	}
}

int main(){
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof head); // 初始化 注意点的编号是从0开始
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(v,u,w); //注意边的指向
	}
	for(int i=1;i<=n;i++){
		add(0,i,0);// 超级源点建边
	}
	spfa(0); //以0为起点
	if(flag==1) return 0;
	for(int i=1;i<=n;i++){
		printf("%d ",dis[i]);
	}
	return 0;
	
}

其实就跟裸的最短路没啥区别。

不要用dijkstra

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值