浅谈差分约束系统
概论(扯淡)
差分约束系统是一种特殊的N元一次方程,它包含
N
N
N个变量
X
1
∼
X
n
X1 \sim Xn
X1∼Xn 以及
M
M
M 个约束条件,每个约束条件都是有两个变量作差构成的,形如
X
i
−
X
j
≤
C
k
Xi - Xj ≤ Ck
Xi−Xj≤Ck 其中 Ck 是常数(一般就是题目给出的),可以是非负数,也可以是负数,
1
≤
i
,
j
≤
N
,
1
≤
k
≤
M
1≤i , j ≤ N , 1 ≤ k ≤ M
1≤i,j≤N,1≤k≤M 我们要解决的问题就是求一组解 X1, X2, …,使得所有约束条件都可以得到满足。
每个约束条件
X
i
−
X
j
≤
C
k
Xi - Xj ≤ Ck
Xi−Xj≤Ck 可以变形为
X
i
≤
X
j
+
C
k
Xi ≤ Xj + Ck
Xi≤Xj+Ck,这和单源最短路问题中的三角形不等式
d
i
s
t
[
y
]
≤
d
i
s
t
[
x
]
+
z
dist[y] ≤ dist[x] + z
dist[y]≤dist[x]+z (注意!!这条不等式是指dis[y]已经为最短路的距离了)灰常相似,于是乎…可以把每个变量 Xi 看做有向图中的每一个结点 i,对于每个约束条件
X
i
−
X
j
≤
C
k
Xi - Xj ≤ Ck
Xi−Xj≤Ck ,从结点 j 向结点 i 连一条长度为 Ck 的有向边。
这
d
i
s
t
[
0
]
=
0
dist[0] = 0
dist[0]=0,已 0 为起点求单源最短路。若图中存在负环,则给定的差分约束系统无解。否则,
X
i
=
d
i
s
t
[
i
]
Xi = dist[i]
Xi=dist[i]就是差分约束系统的一组解。
我扔https://www.lydsy.com/JudgeOnline/problem.php?id=3436
我就是做这道题入门的(滑稽
这是到裸的差分约束系统,题意就是有三种约束条件:
1、 a 比 b 大至少 c
2、 a 比 b 大最多 c
3、 a 等于 b
询问是否成立。
我们可以把这三种约束条件转换为:
1、b - a ≤ -c
2、a - b ≤ c
3、a - b ≤ 0 && b - a ≤ 0
然后我们就可以开心地连边+SPFA了
代码:
#include<bits/stdc++.h>
#define N 40050 //保险,开大一点
using namespace std;
struct edge{
int v,next,c;
}e[N];
int p[N],eid;
void add(int u,int v,int c){
eid++;
e[eid].v=v;
e[eid].c=c;
e[eid].next=p[u];
p[u]=eid;
}
int vis[N],dis[N],f;
void bfs(int u){ //别看函数名,这题SPFA写bfs会T掉的
if(vis[u]) f=1; //判断负环(为啥是vis,因为松弛了呀)
if(f) return;
vis[u]=1;
for(int i=p[u];i;i=e[i].next){
int v=e[i].v;
int c=e[i].c;
if(dis[u]+c<dis[v]){ //松弛
dis[v]=dis[u]+c;
bfs(v);
}
}
vis[u]=0;//记得清空
}
int n,m;
int main(){
memset(dis,0x3f,sizeof(dis));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int c,x,y,z;
scanf("%d",&c);
if(c==1){
scanf("%d%d%d",&x,&y,&z);
add(x,y,-z); //一
}
else
if(c==2){
scanf("%d%d%d",&x,&y,&z);
add(y,x,z);//二
}
else
if(c==3){
scanf("%d%d",&x,&y);
add(x,y,0); //三
add(y,x,0);
}
}
for(int i=1;i<=n;i++){//因为是有向图,所以要每个入度为0点都都要跑
dis[i]=0;
bfs(i);
if(f) break;
}
if(f) printf("No"); else printf("Yes");//输出
return 0;
}
//一次过啦啦啦啦啦啦啦啦
差分约束系统的题主要是看如何转换为最短路
参考资料《信息学奥赛一本通·提高篇》