首先发现这个 \(|a_i-a_j|=1\) 的形式比较接近差分约束,稍微转化一下就是:\(-1\le a_i-a_j\le 1\) 且 \(a_i\neq a_j\)。于是你会发现 \(a_i\neq a_j\) 不是差分约束的条件。
换个角度。容易发现一条边相连的两个点一定奇偶性不同。考虑原图中若存在奇环,那么显然这是自相矛盾的。所以我们可以一开始就把存在奇环的情况判一下。
再回头看 \(a_i\neq a_j\),你会发现在没有奇环的情况下,是不可能出现 \(a_i=a_j\) 的。原因仍然是一条边相连的两个点一定奇偶性不同。所以我们可以大胆地把条件改写为 \(-1\le a_i-a_j\le 1\)。
接下来用 Floyd 跑全源最短路,就可以得到一组解了。那么我们应该如何解决极差最大呢?考虑我们枚举最终极差最大的解中的最小值,以这个点为源点算出它和每个点的最短路。假设从 \(i\) 到 \(j\) 的最短路是 \(L\),它的实际含义是 \(a_j\le a_i+L\)。所以可以发现节点 \(j\) 的最大值就是 \(a_i+L\),所以用 \(L\) 更新极差是正确的。
最后输出答案,就是找到极差最大的那个源点,输出它到其他点的最短路。容易发现输出的所有数都是非负的,所以也不用加上一个特定的数。
// Author: Little09 // Problem: E. Capitalism // Contest: Codeforces Global Round 12 // URL: https://codeforces.com/contest/1450/problem/E // Memory Limit: 256 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> using namespace std; const int N=205,M=2005; int n,m; int a[N],f[N][N],ans=-1,pos; int fa[N*2]; int find(int x) { if (x==fa[x]) return x; return fa[x]=find(fa[x]); } inline void merge(int x,int y) { x=find(x),y=find(y); if (x!=y) fa[x]=y; } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; memset(f,20,sizeof(f)); for (int i=1;i<=n;i++) f[i][i]=0; for (int i=1;i<=2*n;i++) fa[i]=i; for (int i=1;i<=m;i++) { int x,y,z; cin >> x >> y >> z; merge(x+n,y),merge(x,y+n); if (z==1) f[x][y]=1,f[y][x]=-1; else f[x][y]=1,f[y][x]=1; } for (int i=1;i<=n;i++) { if (find(i)==find(i+n))//存在奇环 { cout << "NO"; return 0; } } for (int k=1;k<=n;k++)//Floyd求全源最短路 { for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) { f[i][j]=min(f[i][j],f[i][k]+f[k][j]); } } } for (int i=1;i<=n;i++) { if (f[i][i]<0)//存在负环,差分约束无解 { cout << "NO"; return 0; } int mx=-n-1; for (int j=1;j<=n;j++) mx=max(mx,f[i][j]); if (mx>ans) ans=mx,pos=i;//找到最大值,更新极差 } cout << "YES" << endl; cout << ans << endl; for (int i=1;i<=n;i++) cout << f[pos][i] << " "; return 0; }