您的位置:首页 > 编程语言 > Go语言

kruskal's algorithm.[克鲁斯卡尔算法]

2016-02-23 14:51 483 查看
克鲁斯卡尔算法

假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集
E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。

/本程序用到了并查集的基本操作,不会并查集的请自行学习或参考本代码学习
//getfa为查询祖先,merge为将集合合并,same是判断两个点是否处于同一集合
//getfa操作中使用了路径压缩即return fa[x] = getfa(fa[x]),这样可以减小并查集森林退化所带来的时间复杂度
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN_E 100000
#define MAXN_V 100000
using namespace std;
struct Edge{
int fm,to,dist;
}e[MAXN_E];
int fa[MAXN_V],n,m;
bool cmp(Edge a,Edge b){
return a.dist < b.dist;
}
int getfa(intx){//getfa是在并查集森林中找到x的祖先
if(fa[x]==x) return fa[x];
else return fa[x] = getfa(fa[x]);
}
int same(int x,int y){
return getfa(x)==getfa(y);
}
void merge(intx,inty){
int fax=getfa(x),fay=getfa(y);
fa[fax]=fay;
}
int main(){
scanf("%d%d",&n,&m);//n为点数,m为边数
for(inti=1;i<=m;i++)
scanf("%d%d%d",&e[i].fm,&e[i].to,&e[i].dist);//用边集数组存放边,方便排序和调用
sort(e+1,e+m+1,cmp);//对边按边权进行升序排序
for(int i=1;i<=n;i++)
fa[i]=i;
int rst=n,ans=0;//rst表示目前的点共存在于多少个集合中,初始情况是每个点都在不同的集合中
for(int i=1;i<=m && rst>1;i++)
{
int x=e[i].fm,y=e[i].to;
if(same(x,y)) continue;//same函数是查询两个点是否在同一集合中
else
{
merge(x,y);//merge函数用来将两个点合并到同一集合中
rst--;//每次将两个不同集合中的点合并,都将使rst值减1
ans+=e[i].dist;//这条边是最小生成树中的边,将答案加上边权
}
}
printf("%d\n",ans);
return0;
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: