最小生成树[Kruskal]

来源:互联网 发布:揭秘淘宝刷到单流程图 编辑:程序博客网 时间:2024/06/05 11:56
最小生成树问题:
在一个无向图中,链接每一条边都有相应的权值,如何链接这一些边,让这一个图成为一个连通图,而且让权值之和最小。
根据题目,可以得知生成一棵最小生成树使用的自然需要链接n-1条边使这一个图变成连通图,显然可以使用DFS和BFS来尝试每一条边是否能成立,但是这自然效率低下。所以,生成一棵最小生成树,自然需要使用到一种算法——最小生成树算法。
首先先介绍一下Kruskal算法。
这是一种以贪心为基础的算法。
原理:
生成一棵最小生成树,使用到的自然是不能产生环的边。然后,将所有的边按长度排序,当这条边与之前的边不会组成环时,就选择这一条边。当选择到点数-1的边时,已经形成了一棵最小生成树,那么将它们的权值相加就可以得到答案。
实现:
关于查询环,使用到并查集的算法,并查集在查询环中相对其他算法都要稍快一些,而且使用到压缩路径,判断是否产生环只需要判断是否已经在一棵树中。
通过记录每一条边的权值和两个端点,然后按照权值从小到大排序,选择每一条边,以此,当选择了n-1条边时,就成功生成了这一棵最小生成树。如果到最后选择的边数没有n-1条边,就证明这一个图无法组成连通图。
时间复杂度:O(N+M) 当这一个图的点数很多时,而且是一个稠密图,用Kruskal就很容易超时
参考程序

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>

#define sort std::sort

const int MAXN=20100;

struct Tedge
{
int len,u,v;
Tedge()
{
len=u=v=0;
}
}a[MAXN];//记录每一条边

int n,m;
int fa[MAXN];
int ans;

bool _cmp(Tedge a,Tedge b)
{
return a.len < b.len;
}

int _find(int root)//并查集查询是否在同一环
{
if(fa[root] == root) return root;
else return fa[root]=_find( fa[root] );//压缩路径
}

void _Kruskal()
{
sort(a,a+m,_cmp);

int k=0,sum=0;
for(int i=0;i<m;i++)
{
int dx=_find(a[i].u),dy=_find(a[i].v);

if(dx != dy)//如果不会形成环
{
k++;
sum+=a[i].len;
fa[dx]=dy;//选择这一条边,并且合并
}

if(k == n-1)//当选择了n-1条边时,就退出
{
ans=sum;
break;
}
}
}

int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].len);

for(int i=1;i<=n;i++) fa[i]=i;//初始化并查集

_Kruskal();

printf("%d\n",ans);

return 0;
}


0 0
原创粉丝点击