http://acm.hdu.edu.cn/showproblem.php?pid=1233
http://ac.jobdu.com/problem.php?cid=1040&pid=70
使用克鲁斯卡尔_并查集 求最小生成树
#include <stdio.h>
#include <algorithm> //使用sort(start,end,cmp)函数
using namespace std; //必须在std下
int Tree[100];
int findRoot(int x)
{
if (Tree[x]==-1)
{
return x;
}
else
{
int tmp=findRoot(Tree[x]);
Tree[x]=tmp;
return tmp;
}
}
struct Edge //边结构体
{
int a,b; //边两个顶点编号
int cost; //权值
}edge[5000]; //n*(n-1)/2条边 n<100
bool cmp(Edge a,Edge b) //等效于重载<
{
return a.cost<b.cost;
}
int main()
{
int n,i;
while (scanf("%d",&n)!=EOF && n!=0)
{
for (i=1;i<=n*(n-1)/2;i++) //输入
{
scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].cost);
}
sort(edge+1,edge+1+n*(n-1)/2,cmp); //注意首尾,从1 ~ n*(n-1)/2,权值递增排列
for (i=1;i<=n;i++) //初始所有节点孤立
{
Tree[i]=-1;
}
int ans=0; //最小生成树上初始权值和为0
for (i=1;i<=n*(n-1)/2;i++) //从小到大遍历所有边,两个端点不在一个集合则合并(选取该边)
{
int a=findRoot(edge[i].a); //当前最小边的两个顶点信息
int b=findRoot(edge[i].b);
if (a!=b) //当前两个节点不在一个集合,合并这两个集合
{
Tree[a]=b;
ans+=edge[i].cost;
}
}
printf("%d\n",ans);
}
return 0;
}
//克鲁斯卡尔定理:先将所有边从小到大排序
// 依次选择最小边,若边的两个顶点在不同集合,则合并
// 若最终只剩一个集合且包含所有顶点,则原图是连通图,得到最小生成树,否则原图不连通