CF1450E Capitalism - 差分约束系统 - 最短路 -
题目链接:https://codeforces.com/contest/1450/problem/E
题解:
题目中的等式关系为 \(a_u-a_v=1\) 和 \(|a_u-a_v|=1\)
首先,等式关系不好处理,考虑化成不等式
第一种:\(a_u-a_v\leq 1\) 且 \(a_v-a_u\leq -1\)
第二种:\(a_u-a_v\leq 1\) 且 \(a_v-a_u\leq 1\) 且 \(a_u \neq a_v\)
发现这就是三角形不等式,可以将 \(a_u\) 等价于源点到 \(u\) 的最短距离
\(a_u-a_v \leq c\) 就可以等价于 \((v,u)\) 连了一条长度为 \(c\) 的有向边
因此可以将等式关系对应的图建出来。
此时注意到,如果 \(a_u=a_v\) 的话,一、二种条件均不满足,此时无解。又注意到 \((u,v)\) 是原图的边,因此这个条件就可以等价于原图不是二分图则无解
同样的,如果图中有负环的话,显然也是无法构造出来 \(a\) 的
如何让极差最大?一个重要的观察是发现极差是有上界的,因为 \(a_u-a_v\leq dist(v,u)\)(否则显然可以更新 \(a_u\))。那这个上界能否取到呢?如果我们把 \(v\) 当做源点跑最短路,那么 \(a_u=dist(v,u), a_v=0\),此时就能取到上界。因此跑 floyd,找到 \(dist\) 最大的 \((v,u)\) ,那么将 \(v\) 当做源点,\(a_i=dist(v,i)\) 即可
小细节:判负环可以直接用 \(dist(i,i)<0\),判二分图可以用 \(dist(s,u)=dist(s,v)\)(\((u,v) \in E\))
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 205;
int n,m;
vector<pii>g[maxn];
int dis[maxn][maxn];
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,b;scanf("%d%d%d",&x,&y,&b);
// a_y=a_x+1 -> a_y-a_x <= 1 && a_x-a_y <= -1
if(b == 0)g[x].pb(mpr(y, 1)), g[y].pb(mpr(x, 1));
else g[x].pb(mpr(y, 1)), g[y].pb(mpr(x, -1));
}
memset(dis,0x3f,sizeof dis);
for(int i=1;i<=n;i++)
dis[i][i] = 0;
for(int i=1;i<=n;i++)
for(auto j : g[i])dis[i][j.first] = j.second;
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
for(int i=1;i<=n;i++)
if(dis[i][i] < 0) // 判负环
return puts("NO"), 0;
int res = -INF, r;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
for(auto k : g[j])
if(dis[i][k.first] == dis[i][j]) // 判二分图
return puts("NO"), 0;
if(dis[i][j] > res)
res = dis[i][j],
r = i;
}
puts("YES");
int mx = -INF, mn = INF;
for(int i=1;i<=n;i++)mx = max(mx, dis[r][i]), mn = min(mn, dis[r][i]);
printf("%d\n",mx-mn);
int ans = 0;
for(int i=1;i<=n;i++)
printf("%d ",dis[r][i]);
return 0;
}