CF1450E 资本主义Capitalism(差分约束)

题面

点此看题

没有永远的朋友,只有永远的利益

在这个黑漆漆的社会上,有 n n n 个布衣百姓,他们在利益驱使下成为金钱的奴隶,看不到属于生活的阳光。在茫茫奔途中,他们相互扶持,结交了有 m m m 对朋友关系。

奈何这是个资本主义社会,虽然这 n n n 个人没有人失业,每个人分别有 a i a_i ai 的月薪,但是如果两个人 i , j i,j i,j 满足 a j = a i + 1 a_j=a_i+1 aj=ai+1 ,也就是说 j j j 的月薪刚好比 i i i 的大 1,那么 i i i 就会觊觎 j j j 的成功。

每一对朋友关系中,总有一个人觊觎另一个人,明里交好,暗里嫉妒。

这个社会的收入不平等度定义为 max ⁡ a i − min ⁡ a i \max a_i-\min a_i maxaiminai 。目前已知所有的朋友关系,和部分朋友关系中的嫉妒方向,以及一个范围: 0 ≤ a i ≤ 1 0 6 0\leq a_i\leq 10^6 0ai106 。没错,在利益驱使的剥削下,有的人的月薪可以达到 0 。事实上,这算比较幸运的。

也就是你,看透了这个社会的弊病,大呼着“生活万岁”,把迷茫走失的人们拉回正轨。为了详细地了解这个社会,你打算:求出最大可能的收入不平等度,以及此时可能的每个人的月薪是多少。可能无解。

1 ≤ n ≤ 200 , n − 1 ≤ m ≤ 2   000 1\leq n\leq 200,n-1\leq m\leq2\,000 1n200,n1m2000 .

输入

第一行两个数 n , m n,m n,m

接下来 m m m 行,每行三个数 i , j , b i,j,b i,j,b ,表示 i , j i,j i,j 之间有朋友关系。 b ∈ { 0 , 1 } b\in\{0,1\} b{0,1} ,如果 b = 1 b=1 b=1 ,则 i i i 是嫉妒 j j j 的( a j = a i + 1 a_j=a_i+1 aj=ai+1),如果 b = 0 b=0 b=0 ,则两个人的嫉妒方向不确定。

保证不存在重复的 ( i , j ) (i,j) (i,j),假设每个朋友关系是条无向边,那么这保证是个连通图。

题解

正解是差分约束,想不到?其实应该比较明显的,反正我想不到。

两种情况,两种连边:

  • b = 1 b=1 b=1 :是一个相等关系 a j = a i + 1 a_j=a_i+1 aj=ai+1 ,我们把它拆成 a j ≤ a i + 1 a_j\leq a_i+1 ajai+1 a i ≤ a j − 1 a_i\leq a_j-1 aiaj1
  • b = 0 b=0 b=0 :即 ∣ a i − a j ∣ = 1 |a_i-a_j|=1 aiaj=1 ,姑且先把它看作 ∣ a i − a j ∣ ≤ 1 |a_i-a_j|\leq 1 aiaj1 ,然后转化为 a j ≤ a i + 1 a_j\leq a_i+1 ajai+1 a i ≤ a j + 1 a_i\leq a_j+1 aiaj+1

然后跑 F l o y d \rm Floyd Floyd ,如果任意一个 f i , i < 0 f_{i,i}<0 fi,i<0 ,说明有负环,则无解。

接下来找一个起点 i i i ,使得在满足 ∀ ( u , v ) ∈ E   ,   f i , u ≠ f i , v \forall (u,v)\in E~,~f_{i,u}\not=f_{i,v} (u,v)E , fi,u=fi,v 以及 ∀ j ∈ [ 1 , n ]   ,   f i , j ≥ 0 \forall j\in[1,n]~,~f_{i,j}\geq 0 j[1,n] , fi,j0 的前提下, max ⁡ f i , . . . − min ⁡ f i , . . . \max f_{i,...}-\min f_{i,...} maxfi,...minfi,... 最大。如果找不到这样的 i i i 则无解。找到这个 i i i 后,就令 a j = f i , j a_j=f_{i,j} aj=fi,j 就是了。

最后对于第二种连边,有的人可能会问,没有强制不相等的情况下差分约束,会不会漏掉一些合法情况?实际上不会,如果存在一种情况使得 f i , u ≠ f i , v f_{i,u}\not=f_{i,v} fi,u=fi,v 的话,由于差分约束的性质,因为我们没有连 0 边,一定能使其中一个更小。

CODE

#include<map>
#include<queue>
#include<cmath>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 205
#define ENDL putchar('\n')
#define LL long long
#define DB double
#define lowbit(x) ((-x) & (x))
LL read() {
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
	return f * x;
}
int n,m,i,j,s,o,k;
int ed[MAXN][MAXN];
int g[MAXN][MAXN];
int main() {
	n = read();m = read();
	for(int i = 1;i <= n;i ++) {
		for(int j = 1;j <= n;j ++) g[i][j] = 1000000;
		g[i][i] = 0;
	}
	for(int i = 1;i <= m;i ++) {
		s = read();o = read();k = read();
		if(k == 1) { // ai = aj-1 , aj <= ai+1 ^ ai <= aj-1
			g[s][o] = 1; g[o][s] = -1;
		}
		else { // ai <= aj+1 ^ aj <= ai+1
			g[s][o] = 1; g[o][s] = 1;
		}
		ed[s][o] = ed[o][s] = 1;
	}
	for(int k = 1;k <= n;k ++) {
		for(int i = 1;i <= n;i ++) {
			for(int j = 1;j <= n;j ++) {
				g[i][j] = min(g[i][j],g[i][k] + g[k][j]);
			}
		}
	}
	for(int i = 1;i <= n;i ++) {
		if(g[i][i] < 0) {
			printf("NO\n");return 0;
		}
	}
	int as = 0,ans = -1;
	for(int i = 1;i <= n;i ++) {
		bool flag = 1;
		for(int s = 1;s <= n;s ++) {
			for(int o = 1;o <= n;o ++) {
				if(ed[s][o] && g[i][s] == g[i][o]) flag = 0;
			}
		}
		if(!flag) continue;
		int mi = 1000000,ma = 0;
		for(int j = 1;j <= n;j ++) {
			mi = min(mi,g[i][j]);
			ma = max(ma,g[i][j]);
		}
		if(mi < 0) continue;
		if(ans < ma-mi) {
			ans = ma-mi; as = i;
		}
	}
	if(!as) {printf("NO\n");return 0;}
	printf("YES\n%d\n",ans);
	for(int i = 1;i <= n;i ++) printf("%d ",g[as][i]);ENDL;
	return 0;
}
posted @ 2021-07-13 10:04  DD_XYX  阅读(57)  评论(0编辑  收藏  举报