题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1233
krusal算法裸题
krusal算法是基于“避圈法”的思想,避圈法可以用并查集实现。
krusal又是基于贪心思想的。
先把所有边按从小到大的顺序排序。然后,逐个选取,在选取的过程中,如果查询到两个端点不在同一个集合,那么必然选择它作为最小生成树的一部分,并合并这两个端点。
如果查询到这两个端点在同一个集合里,那么继续选取下一条边,直至选取了n-1条边,算法结束。
算法复杂度为排序的复杂度。O(e*log(e))
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=10005;
struct node { int from,to,len;} edge[maxn];//储存边的数据结构
int n,fa[maxn],m,ans,q;
bool cmp(node a,node b) { return a.len<b.len; }//边按从小到大的顺序排列
int Find(int x)
{
if(fa[x]==x) return x;
return fa[x]=Find(fa[x]);
}
void Merge(int x,int y)
{
x=Find(x),y=Find(y);
if(x!=y) fa[y]=x;
}
int kruskal()
{
sort(edge,edge+m,cmp);//边排序
for(int i=0;i<=n;i++) fa[i]=i;//初始化并查集
ans=0;
for(int i=0;i<m;i++)//一条边的两个端点不在同一个集合,则选它,并合并端点
if(Find(edge[i].from)!=Find(edge[i].to)) Merge(edge[i].from,edge[i].to),ans+=edge[i].len;
return ans;
}
int main()
{
while(cin>>n,n)
{
m=n*(n-1)/2;
for(int i=0;i<m;i++) cin>>edge[i].from>>edge[i].to>>edge[i].len;
cout<<kruskal()<<endl;
}
return 0;
}