/*在这一道题中并查集的作用是:将同一个监狱里的罪犯合并到一起。 思路:将每对罪犯之间的怨气值从大到小排序,再依次把他们分到不 同的两个监狱里,当发现这一对罪犯已经在同一个监狱里时,就说明 他们已经不能再分开了(分开了就不是最优了)。此时,这一对罪犯 之间的怨气值就是答案。值得注意的是,当没有冲突发生时,要记得 输出0。那么,我们应该如何用并查集实现以上的思路呢?首先说几个 关键词语的含义: 1、“敌人”:如果一对罪犯被分到两个不同的监狱里,那么他们就互为“敌人”。 2、“朋友”:如果一对罪犯被分到一个监狱里,那么他们就互为“朋友”。 需要明确的一点是“敌人”的“敌人”,就是“朋友”。 当分开一对罪犯时(假设他们的名字叫x和y),若x还没有“敌人”,那么y就 是他的“敌人”(因为他们被分开了嘛);否则就把y所在的集合与x的“敌人” 所在的集合合并,因为x是y的“敌人”,所以x的“敌人”就是y的“敌人”的 “敌人”(即朋友),将y所在的集合与x的“敌人”所在的集合合并是因为x的 “敌人”和x关在不同的监狱里,而y又和x关在不同的监狱里,并且只有两个监 狱,所以x的“敌人”所在的集合里面的人和y所在的集合里面的人一定关在一 个监狱里。对y的“敌人”也这样处理一遍就可以了。*/ #include<iostream> #include<cstdio> #include<algorithm> using namespace std; struct edge//存罪犯之间的怨气关系 { int u; int v; int w; }e[100005]; bool cmp(edge x,edge y)//将怨气值从大到小排序的排序函数 { return x.w>y.w; } //f为用作实现并查集的数组,表示的是第i个罪犯的“祖先”是谁,enemy储存的是第i个罪犯的某个敌人 int f[20005],enemy[20005]; int find_(int x)//并查集查找函数 { if(f[x]==x) return x; return f[x]=find_(f[x]); } void merge_(int x,int y)//并查集合并函数 { int t1=find_(x),t2=find_(y); if(t1!=t2) f[t2]=t1; return; } int main() { int n=0,m=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) f[i]=i;//并查集初始化 for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); sort(e+1,e+m+1,cmp);//将怨气值从大到小排序 for(int i=1;i<=m;i++) { if(find_(e[i].u)==find_(e[i].v))//如果这一对罪犯已经在同一个监狱里 { printf("%d",e[i].w);//直接输出他们之间的怨气值 return 0;//结束程序 } //如果这一对罪犯仍能分开 if(!enemy[e[i].u]) enemy[e[i].u]=e[i].v;//如果u还没有敌人,那么v就是他的敌人 else merge_(e[i].v,enemy[e[i].u]);//否则,就将v与u的敌人合并 if(!enemy[e[i].v]) enemy[e[i].v]=e[i].u;//如果v还没有敌人,那么u就是他的敌人 else merge_(e[i].u,enemy[e[i].v]);//否则,就将u与v的敌人合并 } printf("%d",0);//记得输出0 return 0; }