CF1450E Capitalism 题解
作者:互联网
首先发现这个 \(|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;
}
标签:le,int,题解,短路,CF1450E,fa,极差,Capitalism,find 来源: https://www.cnblogs.com/irty/p/16694581.html