差分约束
运用范围:(求解多个二元不等式组)
例如:
X
1
?
X
2
<
=
0
X1-X2<=0
X1?X2<=0
X
3
?
X
4
<
=
8
X3-X4<=8
X3?X4<=8
X
2
?
X
5
<
=
?
9
X2-X5<=-9
X2?X5<=?9
X
3
?
X
1
<
=
7
X3-X1<=7
X3?X1<=7
X
5
?
X
2
<
=
0
X5-X2<=0
X5?X2<=0
.
.
.
.
.
.
......
......
原理:
- 对于这类不等式组,其解集要么无解,要么有无数解。(所有数同时加上X,其差值不会改变)
- 我们可以用最短路的思想解决这类问题
在对一张图跑完最短路算法后,对任意一条由u指向v的边都存在不等式: Dis[v]<=Dis[u]+Len[u][v] 将这个不等式移项有: Dis[v]-Dis[u]<=Len[u][v] 这与不等式:
X
1
?
X
2
<
=
M
X1-X2<=M
X1?X2<=M神似。 所以我们只需要把
X
1
X1
X1当作v点,
X
2
X2
X2当作u点,再向两点连一条边长为m的边即可。 最后这个不等式组就会变成一张图。
如何判断是否有解?
当你构造的这张图存在负权回路就表示无解 (若存在负权回路则Dis数组会无限减少,最终不满足不等式)
如何求出一组具体的解
- 新建一个原点
X
0
X0
X0,把
X
0
X0
X0向所有点连一条权值为0的边
- 以
X
0
X0
X0为起点跑一遍最短路。
- 对每一个节点的Dis[i],就是
X
i
Xi
Xi的一个可行解
- 若把Dis[
X
0
X0
X0]设置为A时,所有其它节点的值都会小于A(不等式定义)
AC代码:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
#define H 500005
#define LL long long
int N,M;
int Dis[H],ED[H],LA[H],NT[H],LEN[H],tot,Cnt[H];
queue<int>Q;
void LB(int u,int v,int d){
ED[++tot]=v;NT[tot]=LA[u];LA[u]=tot;LEN[tot]=d;
}
bool flag=1,MK[H];
void SPFA(int S){
for(int i=1;i<=N;i++)Dis[i]=1000000000;
Q.push(S);
MK[S]=1;Cnt[S]++;
while(!Q.empty()){
int x=Q.front();
Q.pop();MK[x]=0;
for(int i=LA[x];i;i=NT[i]){
int y=ED[i];
if(Dis[y]>Dis[x]+LEN[i]){
Dis[y]=Dis[x]+LEN[i];
if(!MK[y]){
MK[y]=1;Cnt[y]++;
if(Cnt[y]>N){
flag=0;return;
}
Q.push(y);
}
}
}
}
}
int main(){
scanf("%d%d",&N,&M);
for(int i=1;i<=M;i++){
int u,v,d;
scanf("%d%d%d",&v,&u,&d);
LB(u,v,d);
}
for(int i=1;i<=N;i++)LB(0,i,0);
SPFA(0);
if(!flag)puts("NO");
else{
for(int i=1;i<=N;i++)printf("%d ",Dis[i]);
}
}
|