Luogu P1525 关押罪犯

Dexription:

给你m对矛盾关系,每对关系分别涉及到x,y两人,矛盾值为w
请你判断分配x和y到两个集合中,能否避免冲突
如能避免请输出0,如果冲突不可避免,请输出最小的矛盾值

Analysis:

并查集:
两个人a,b有仇,那么把他们放在一起显然会打起来,那么我们还不如把a与b的其他敌人放在一起,
因为这样可能会出现“敌人的敌人就是朋友”的情况,恰好a与b的其他敌人之间没有矛盾,那么他们就可以放在同一个集合中,反之b对a亦然。
(1)先把所有的矛盾关系按照矛盾值从大到小排一遍序,
(2)接下来每次操作取出一个关系,看矛盾的两个人x和y是否已经分配到同一个集合中(并查集找父亲即可),那么还分如下两种情况:
如果在一起那么显然会打起来(会出现矛盾),那么直接输出当前的边权(矛盾值)即可(此时保证是最小矛盾值,因为已经排序了)
如果不在同一组,则按照“敌人的敌人就是朋友”的原则,把x与y的其他敌人分在同一组,y与x的其他敌人分在同一组

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 20100,M = 100010;
struct criminal{
	int x,y,w;
}e[M];
int set[N],enm[N],n,m;
bool cmp(const criminal &a,const criminal&b) {
	return a.w > b.w;
}
int find(int x)
{
	if(set[x] == x) return x;
	return set[x] = find(set[x]);
}
inline void Merge(int x,int y)
{
	set[find(y)] = find(x);
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;++i) set[i] = i;
	for(int i = 1;i <= m;++i)
	{
		scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
	}
	sort(e+1,e+1+m,cmp);
	for(int i = 1;i <= m;++i)
	{
		int x = find(e[i].x),y = find(e[i].y);
		if(find(x) == find(y))
		{
			printf("%d",e[i].w);
			return 0;
		}
		else{
			if(!enm[x])
			{
				enm[x] = y;
			}
			else{
				Merge(enm[x],y);
			}
			
			if(!enm[y])
			{
				enm[y] = x;
			}
			else{
				Merge(enm[y],x);
			}
		}
	}
	printf("0");
    return 0;
}
岂能尽如人意,但求无愧我心
原文地址:https://www.cnblogs.com/Zforw/p/11348061.html