题目链接:
题意:
有M个点 N条边 求构成最小生成树的最大边 和生成树所有边的两个端点
裸最小生成树 加上了两个优化
1.路径压缩:查找x元素的根节点d时,将x的所有父亲节点全部直接变成根节点的子节点
以减少下次查找的查找时间
2.在并查集 并 的过程中 考虑两个节点谁的子节点多,少的作为子节点
关于fa[]数组:只有集合的根节点为负数,而且负数的绝对值表示该集合的元素个数(-1累加上去的);如果x不是根节点,则fa[x]表示x的父节点
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int u,v,w;
}edge[16005];
int fa[1005],ans[1005][2];
int maxx,m,n,s,nn;
int cmp(node a,node b)
{
return a.w<b.w;
}
void init()
{
s=0,maxx=0,nn=0;
memset(fa,-1,sizeof(fa));
}
int find(int x)
{
int t,d=x;
while(fa[d]>=0)
d=fa[d];
while(x!=d)
{
t=fa[x];
fa[x]=d;
x=t;
}
return d;
}
void Kruskal()
{
int r1,r2,i,j,k;
for(i=0;i<s;i++)
{
r1=find(edge[i].u);r2=find(edge[i].v);
if(r1!=r2)
{
if(edge[i].w>maxx)
maxx=edge[i].w;
ans[nn][0]=edge[i].u;ans[nn++][1]=edge[i].v;
int ss=fa[r1]+fa[r2];
if(fa[r1]<fa[r2])
{
fa[r1]=ss;
fa[r2]=r1;
}
else
{
fa[r1]=r2;
fa[r2]=ss;
}
}
if(nn==m-1)
break;
}
return ;
}
int main()
{
int a,b,c,i;
while(~scanf("%d%d",&m,&n))
{
init();
while(n--)
{
scanf("%d%d%d",&a,&b,&c);
edge[s].u=a;edge[s].v=b;
edge[s++].w=c;
}
sort(edge,edge+s,cmp);
Kruskal();
cout<<maxx<<endl<<nn<<endl;
for(i=0;i<nn;i++)
cout<<ans[i][0]<<' '<<ans[i][1]<<endl;
}
return 0;
}