luogu P1525 关押罪犯

题目传送门:https://www.luogu.org/problemnew/show/P1525



题意:

有两个监狱,n个罪犯,有m组罪犯之间有怒气,求让所有罪犯都关进监狱的最小的怒气值(最小怒气值为两个监狱的最大怒气值)。注意:有两个罪犯x,y,有且仅有x,y在同一个监狱时才有怒气值。



思路:

从数据范围和题意可以看出并查集。

并查集类型的题目需要记住:朋友的敌人是我的敌人,敌人的敌人是我的朋友。

那么我们可以贪心地想到:越大的怒气值的一组罪犯应分在两个不同的监狱里。



解法:

想到这一点,我们就可以知道可以进行排序(关键字为怒气值),将两个罪犯分在不同的监狱,即使他们的祖先不同。

那么,我们就知道,如果当前的两个罪犯的祖先相同(他们必须在同一监狱),那么他们的怒气值即为所求(因为怒气值从大到小排序,这是当前在同一监狱的最大怒气值)。

否则呢?对于每一个罪犯,他所对的另一个罪犯就为他的敌人;如果他已经有敌人了,那么他的敌人就和另一个罪犯为朋友关系,在同一个监狱(因为我的敌人和我的另一个敌人为朋友),将他们合并即可。



代码:

#include<cstdio>
#include<algorithm>
using namespace std;
	struct node{int x,y,z;} a[200000];
	int n,m;
	int fa[30000],foe[30000];//fa[i]表示i的祖先,foe[i]表示i的敌人
bool cmp(node x,node y)
{
	return x.z>y.z;
}
int find(int x)//并查集路径优化,寻找祖先
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
void work(int x,int y)//合并
{
	fa[find(x)]=find(y);
}
int main()
{
	int x,y,z;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)
		scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].z);
	for(int i=1;i<=n;i++)
		fa[i]=i;
	sort(a+1,a+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
		int x=a[i].x,y=a[i].y,t1=find(x),t2=find(y);
		if(t1==t2)
		{
			printf("%d",a[i].z);
			return 0;
		}
		if(!foe[x]) foe[x]=y; else work(foe[x],y);
		if(!foe[y]) foe[y]=x; else work(foe[y],x);
	}
	printf("0");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值