前置知识
差分约束系统
如果一个系统由 \(n\) 个变量和 \(m\) 个约束条件组成,形成 \(m\) 个形如 \(a_i-a_j\le k\) 的不等式(\(i,j∈[1,n]\),\(k\) 为常数),则称其为差分约束系统。
如何求出一个差分约束系统的解?
\(a_i-a_j\le k \to a_i\le a_j+k\)。
这类似最短路中的三角不等式 \(dis_v \le dis_u+w_{u,v}\)。
对于 \(a_i-a_j\le k\),连接一条权值为 \(k\) 的边 \(j \to i\)。
最后建立超级源点 \(0\),向各个点连权值为 \(0\) 的边。
从超级源点开始跑一遍最短路,就可以求出一组可行解。
无解
正如最短路可能会出现无解情况。如果建出的图中存在负环,则该差分约束系统无解。
模板
Solution
模板题。根据上述内容做即可。
注意有一个坑点:由于超级源点的存在,实际点数为 \(n+1\),判负环不要写错了。
Code
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define go(i,x,y) for (int i=x;i<=y;i++)
using namespace std;
template <typename type>
void read(type &x){
char c=getchar();
int F=0;
while (c!='-' && (c<'0' || c>'9')) c=getchar();
if (c=='-') F=1,x=0; else x=(c^48);
c=getchar();
while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
if (F) x=-x;
}
template <typename type>
void write(type x){
if (x<0) putchar('-'),x=-x;
if (x>9) write(x/10);
putchar(x%10+'0');
}
const int M=5e3+5,N=5e3+5;
struct edge{
int to,nex,w;
}e[M+N];
int h[N],hcnt;
void add_edge(int x,int y,int z){
e[++hcnt]=(edge){y,h[x],z};
h[x]=hcnt;
}
int n,m,x,y,z,dis[N],cnt[N],vis[N];
queue <int> q;
bool SPFA(int s){
memset(dis,0x3f,sizeof(dis));
// memset(vis,0,sizeof(vis));
// memset(cnt,0,sizeof(cnt));
while (!q.empty()) q.pop();
dis[s]=0,vis[s]=1,cnt[s]=1;
q.push(s);
while (!q.empty()){
int x=q.front();
q.pop();
vis[x]=0;
for (int i=h[x]; i; i=e[i].nex){
int y=e[i].to;
if (dis[x]+e[i].w<dis[y]){
dis[y]=dis[x]+e[i].w;
if (!vis[y]){
if (++cnt[y]>=n+1) return false;
vis[y]=1,q.push(y);
}
}
}
}
return true;
}
int main(){
read(n),read(m);
go(i,1,m) read(x),read(y),read(z),add_edge(y,x,z);
go(i,1,n) add_edge(0,i,0);
if (SPFA(0)){
go(i,1,n) write(dis[i]),putchar(' ');
} else{
puts("NO");
}
return 0;
}
浙公网安备 33010602011771号