题意
给n个节点,m条无向的边,要求把这n个节点分配到两个集合当中,保证两个集合中存在同一集合的两点存在的边的权值的最大值最小,如果可以把节点分配到两个集合中保证每个集合中任意两点间均不存在边,则输出0。
思路
开一个两倍节点数大小的数组作为并查集,第一倍保存同一集合中的节点的祖先,第二倍保存不同集合中的点的祖先,将所给边从大到小排序,再从大到小遍历每一条边,如果边的两个节点第一倍的祖先不同,则将两个节点分配到不同的集合当中,即合并第一个节点的第一倍集合与第二个节点的第二倍集合,同时合并第二个节点的第一倍集合和第一个节点的第二倍集合。如果遍历到的边的两个节点的第一倍集合的祖先相同,则说明这两个节点必在同一集合里,这也是最优的情况了,此时输出权值,程序结束。否则完成遍历还没有找到,则输出0。
上代码
#include <iostream>
#include <algorithm>
using namespace std;
int n, m;
int fa[40005];
int findfather(int x)
{
return x==fa[x]?x:fa[x] = findfather(fa[x]);
}
struct Edge
{
int x, y;
int c;
bool operator < (const Edge a)
{
return c>a.c;
}
}e[100005];
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1; i<=2*n; i++)
{
fa[i] = i;
}
for(int i=1; i<=m; i++)
{
cin>>e[i].x>>e[i].y>>e[i].c;
}
sort(e+1, e+m+1);
for(int i=1; i<=m; i++)
{
int t1 = findfather(e[i].x);
int t2 = findfather(e[i].y);
int t3 = findfather(e[i].x+n);
int t4 = findfather(e[i].y+n);
if(t1 != t2)
{
fa[findfather(e[i].x+n)] = findfather(e[i].y);
fa[findfather(e[i].y+n)] = findfather(e[i].x);
}
else
{
cout<<e[i].c<<endl;
return 0;
}
}
cout<<"0"<<endl;
return 0;
}