差分约束
给定包含 $n$ 个未知数 $x_1,x_2,\cdots,x_n$ 的不等式组:
\[\begin{cases} x_{a_1}-x_{b_1}\leq y_1\\ x_{a_2}-x_{b_2}\leq y_2\\ \cdots\\ x_{a_m}-x_{b_m}\leq y_m \end{cases}\]求其任意整数解,或报告无解。
最短路
考虑将 $x_{a_i}-x_{b_i}\leq y_i$ 转化,得到 $x_{a_i}\leq x_{b_i}+y_i$。考虑最短路问题,设 $\textit{dis}x$ 为 $x$ 的最短路,发现对于边 $(x,v)$,在最短路确定之后,有 $\textit{dis}_v\leq\textit{dis}{x}+w_{x,v}$。
因此考虑在一张有向图上从 $b_i$ 向 $a_i$ 连权值为 $y_i$ 的边,跑最短路即可。
最短路的起点一般设置一个不存在的 $0$ 号点,$0$ 向所有点连权值为 $0$ 的有向边。相当于 $x_0\leq x_i$。
无解即存在负环,Bellman-Ford 判断即可。
AC 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=5e3,inf=0x3f3f3f3f;
int n,dis[N+1];
vector<pair<int,int>>g[N+1];
bool BellmanFord(){
memset(dis,0x3f,sizeof(dis));
dis[0]=0;
for(int i=0;i<=n;i++){
bool flag=true;
for(int x=0;x<=n;x++){
if(dis[x]==inf){
continue;
}
for(auto [v,w]:g[x]){
if(dis[x]+w<dis[v]){
dis[v]=dis[x]+w;
flag=false;
}
}
}
if(flag){
return false;
}
}
return true;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int m;
cin>>n>>m;
for(int i=1;i<=n;i++){
g[0].push_back({i,0});
}
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
g[v].push_back({u,w});
}
if(BellmanFord()){
cout<<"NO\n";
}else{
for(int i=1;i<=n;i++){
cout<<dis[i]<<' ';
}
}
cout.flush();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}