[CF1450E] Capitalism

前言

资本主义终将被社会主义取代!

题目

CF

洛谷

讲解

其实吧这道题如果能想到差分约束就基本搞定了。

  • \(b=1\)\(a_u+1=a_v\),那么我们可以看做 \(a_u+1\ge a_v\)\(a_u+1\le a_v\)
  • \(b=0\)\(|a_u-a_v|=1\),我们可以看做 \(a_u+1\ge a_v\)\(a_v+1\ge a_u\)

连边跑最短路,如果存在负环即无解。由于是多源最短路,这里我们采用 \(\tt Floyd\) 算法。

之后我们要求极差最大,枚举起点算极差即可。值得注意的是有连边的点权值不能相等,如果相等,那么此情况应舍去。

那么可能会有人问了,你上面的条件是不等式,你只用判断相等就可以判断无解吗?

是的,因为如果连边,两个点的权值差一定相差为 \(1\),如果为 \(0\),即为不合法,应该舍去。

最后值得注意的是因为求出来的最短路可能有负数,输出的时候随便加个大一点的正数使其变为正数即可。

代码

int dis[MAXN][MAXN];
void Add_Edge(int x,int y,int z){dis[x][y] = Min(dis[x][y],z);}
bool check()
{
	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 0;
	return 1;
}
pair<int,int> e[MAXM];

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j <= n;++ j)
			if(i ^ j) dis[i][j] = INF;
			else dis[i][j] = 0;
	for(int i = 1;i <= m;++ i)
	{
		int u = Read(),v = Read(),w = Read();
		Add_Edge(u,v,1);
		if(w) Add_Edge(v,u,-1);//au+1 = av
		else Add_Edge(v,u,1);//|au - av| = 1
		e[i] = make_pair(u,v);
	}
	if(!check()) {printf("NO\n");return 0;}
	int ret = -1,jc = -1;
	for(int u = 1;u <= n;++ u)
	{
		bool fk = 1;
		for(int i = 1;i <= m && fk;++ i)
			if(dis[u][e[i].first] == dis[u][e[i].second])
				fk = 0;
		if(!fk) continue;
		int MAX = -INF,MIN = INF;
		for(int v = 1;v <= n;++ v)
		{
			MAX = Max(MAX,dis[u][v]);
			MIN = Min(MIN,dis[u][v]);
		}
		if(jc < MAX - MIN) jc = MAX-MIN,ret = u;
	}
	if(ret < 0) {printf("NO\n");return 0;}
	printf("YES\n");
	Put(jc,'\n');
	for(int i = 1;i <= n;++ i) Put(dis[ret][i]+100000,' ');
	return 0;
}
posted @ 2021-07-13 09:43  皮皮刘  阅读(72)  评论(0编辑  收藏  举报