最小生成树 克鲁斯卡尔(Kruskal)算法求最小生成树

Kruskal算法的过程:
(1) 将全部边按照权值由小到大排序。 (2) 按顺序(边权由小到大的顺序)考虑没条边,只要这条边和我们已经选择的边步构成圈,就保留这条边,否则放弃这条边。
算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通。
图中的路径按照权值的大小的排序为
AF 1;
BE 4;
BD 5;
BC 6;
DC:10;
BF 11;
DF 14;
AE 16;
AB 17;
EF 33;
算法的处理过程如下
先选A,F不在一个集合中,所以选AF。
E,D不在一个一个集合中,可以选
 
B,D不在一个集合中,可选BD
B,C不在一个集合中,可选BC
B,D在同一个集合中,放弃BD,
选BF
至此所有的的顶点都连起来,算法结束= =
 
 
;u[i],v[i]分别储存顶点,w[i]保存权值,用r[i]表示边的序号
这里对权值的排序可以这样写
1 bool cmp(int i,int j)
2 {
3     return w[i]<w[j];
4 }
5 sort(r,r+m,cmp);

然后我们需要考虑新加入的边会不会和先前选好的边形成环,即判断u,v,是否在同一连通分量中,这里我们用并查集来查找,然后合并
f[x]表示x的,合并只需条语句f[x]=y;。然后实现实现克鲁斯卡尔的算法的代码如下

 
 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 #define maxn 5000
 7 int f[maxn];
 8 int u[maxn],v[maxn],w[maxn],r[maxn];
 9 int n,m;
10 bool cmp(int i,int j)
11 {
12     return w[i]<w[j];
13 }
14 int find(int x)
15 {
16     return f[x]==x?x:find(f[x]);
17 }
18 __int64 Kruskal()
19 {
20     __int64 ans=0;
21     for(int i=1;i<=n;i++)
22     {
23         f[i]=i;
24     }
25     for(int i=1;i<=m;i++)
26     {
27         r[i]=i;
28     }
29     sort(r+1,r+m+1,cmp);
30     for(int i=1;i<=m;i++)
31     {
32         int e=r[i];
33         int x=find(u[e]);
34         int y=find(v[e]);
35         if(x!=y)
36         {
37             ans+=w[e];
38             f[x]=y;
39         }
40     }
41     return ans;
42 }
43 int main()
44 {
45     while(~scanf("%d",&n)&&n)
46     {
47         memset(r,0,sizeof(r));
48         //memset(u,0,sizeof(u))
49         m=n*(n-1)/2;
50     for(int i=1;i<=m;i++)
51     {
52         scanf("%d %d %d",&u[i],&v[i],&w[i]);
53     }
54     printf("%lld
",Kruskal());
55 }
56 }
 
 
 

原文地址:https://www.cnblogs.com/NaCl/p/9580183.html