Kruskal算法的过程:
(1) 将全部边按照权值由小到大排序。 (2) 按顺序(边权由小到大的顺序)考虑没条边,只要这条边和我们已经选择的边步构成圈,就保留这条边,否则放弃这条边。
算法 成功选择(n-1)条边后,形成一个棵最小生成树,当然如果算法无法选择出(n-1)条边,则说明原图不连通。
算法 成功选择(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\n",Kruskal()); 55 } 56 }