题目链接:
https://www.luogu.com.cn/problem/P1525
参考博客:
https://www.luogu.com.cn/blog/chtholly20094/solution-p1525
这个博客写的很棒,建议复习时再看
算法:
并查集
思路:
1:并查集:但因为它们带有权值,因此排序是必须的,我们要尽可能让危害大的罪犯在两个监狱里
2:那么,再结合敌人的敌人和自己在一个监狱的规律合并
3:当查找时发现其中两个罪犯不可避免地碰撞到一起时,只能将其输出并结束;没有冲突时输出0
#include <bits/stdc++.h>
using namespace std;
struct date//结构体便于排序的变换
{
int x,y,z;
}f[100002];
int n,m,a[20002],b[20002],i;
inline void init()
{
for(int i=1;i<=n;i++)
a[i]=i;
}
inline bool cmp(date a,date b)//重写cmp函数
{
return a.z>b.z;
}
inline int find(int x)
{
if(a[x]!=x)a[x]=find(a[x]);
return a[x];
}
//并查集合并
inline void ad(int x,int y)
{
x=find(a[x]);
y=find(a[y]);
if(x!=y)a[x]=y;
}
//判断是否在同一棵树中,即是否在同一个监狱中
inline bool check(int x,int y)
{
x=find(x);
y=find(y);
if(x==y)return true;
else return false;
}
int main()
{
ios::sync_with_stdio(0);
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++)
scanf("%d%d%d",&f[i].x,&f[i].y,&f[i].z);
sort(f+1,f+m+1,cmp);
//写的很巧妙,到m+1恰好说明没有发生冲突 ,check()函数将会返回true,cout<<f[m+1].z=0
for(int i=1;i<=m+1;i++)
{
if(check(f[i].x,f[i].y))//如果两个罪犯已经在同一监狱就输出 ,并退出
{
printf("%d",f[i].z);
break;
}
else//a数组代表他下标的朋友,在同一棵树中,同一个强连通分量中;b数组代表他下标的敌人
{//如果f[i].x没有敌人就把f[i].y标记为敌人,如果有敌人了,就把敌人f[i].y和敌人b[f[i].x]合并
if(!b[f[i].x])b[f[i].x]=f[i].y;
else ad(b[f[i].x],f[i].y);
if(!b[f[i].y])b[f[i].y]=f[i].x;
else ad(b[f[i].y],f[i].x);
}
}
return 0;
}