您的位置:首页 > 其它

最小生成树算法Kruskal详解

2018-03-26 18:03 211 查看

一、算法概述

最小生成树(Minimum Spanning Tree,MST):或者称为最小代价树Minimum-cost Spanning Tree:对无向连通图的生成树,各边的权值总和称为生成树的权,权最小的生成树称为最小生成树。
最小生成树问题其实就是求一棵怎样的树可以遍历每个节点,且总权值最小。

本文介绍用Kruskal算法解决最小生成树问题。

二、算法步骤

1、将连通图看做无边的散点,每个散点即为自己的父节点。
2、将每条边按照从小到大的顺序排列,每次从中取最小的边加入散点图。
3、加入时需要满足两个点连接后不能出现连通图。
     要想确保不出现连通图,则两个点在连接前应属于不同的集合(树)。所以需要判定它们是否在一个集合中。
     方法是使用并查集,关于并查集的内容请参照:https://blog.csdn.net/hacker_wind/article/details/79687134
4、重复步骤直至散点图变为连通图。所以定义一个计数器,当计数器的数值等于节点个数时,程序退出。

三、代码及测试样例


给出如上图所示连通图,求其最小生成树。由图可知一共有6个节点,10条边。初始化其为散点图,将边按照权值由小到大加入图中,则顺序为AC,DF,BE,CF,当BC、AD、AC权值都为5时,程序会按照输入顺序先后进行判定。假设输入顺序为AD、BC、CD,则发现ACDF构成了连通图,所以将AD边舍去。BC边加入后未构成连通图,且所有点实现了连通,则程序结束。

最后得到的最小生成树如上图所示。代码如下:#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
//#define PI 3.14159265358979323
#define inf 0x3f3f3f3f
int pre[1005];//并查集中用于记录父节点的数组
int n,m;
int ans;
struct edges
{
int u,v,w;//u、v为一条边的两个节点,w为边的权重
}e[1005];
bool cmp(edges a,edges b)
{
return a.w<b.w;//对边进行排序
}
void Init()//初始化散点图,每个散点的父节点为自己本身
{
for(int i=0;i<m;i++)
pre[i]=i;
}
int Find(int x)//并查集中寻找父节点的函数
{
int r=x;
while(pre[r]!=r)
r=pre[r];
return r;
}
void join(int a,int b)//将两个不在同一集合的点连通起来
{
pre[b]=a;
}
void kruskal()
{
int sumw=0;//权值总和
int n=0;//计数器,记录加入树中节点的个数
Init();
int u,v;
for(int i=0;i<m;i++)
{
u=e[i].u;
v=e[i].v;
int fx=Find(u);
int fy=Find(v);
if(fx!=fy)
{
cout<<u<<" "<<v<<" "<<e[i].w<<endl;
sumw+=e[i].w;
n++;
join(fx,fy);
}
if(n==m-1)
break;
}
cout<<"The weight of MST is "<<sumw<<endl;
}
int main()
{
cin>>n>>m;//n为节点总个数,m为边数
for(int i=0;i<m;i++)
cin>>e[i].u>>e[i].v>>e[i].w;
sort(e,e+m,cmp);
kruskal();
return 0;
}
/*
测试样例
6 10
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
*/运行结果如下图所示:

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