kruskal克鲁斯卡尔算法

转自 http://blog.chinaunix.net/uid-26602509-id-3200422.html

给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树.

求最小生成树的算法
(1) 克鲁斯卡尔算法
图的存贮结构采用
边集数组,且权值相等的边在数组中排列次序可以是任意的.该方法对于边相对比较多的不是很实用,浪费时间.

方法:将图中边按其权值由小到大的次序顺序选取,若选边后不形成回路,则保留作为一条边,若形成回路则除去.依次选够(n-1)条边,即得最小生成树,(n为顶点数)就是一个贪心算法;

Kruskal适合
一维数组来管理数据 ;
 
第一步:由边集数组选第一条边

第二步:选第二条边,即权值为2的边

第三步:选第三条边,即权值为3的边

第四步:选第四条边,即权值为4的边

第五步:选第五条边




  1. /*
  2.  * Introduction to Algorithms
  3.  * Chapter 23 --- MST.Kruskal
  4.  * Tanky Woo @ www.WuTianQi.com
  5.  * 2012.1.7
  6.  */
  7.  
  8. #include <iostream>
  9. #include <algorithm>
  10. using namespace std;
  11.  
  12. const int maxint = 999999;
  13.  
  14. typedef struct Road{
  15.     int c1, c2; // a到b
  16.     int value; // 权值
  17. }Road;
  18.  
  19. int no;
  20. int line;//记录实际关系数
  21. Road road[100];//设一个比较大的值,实际看输入最小生成树中:边数e=n-1
  22. int node[101];//最小生成树:n顶点数
  23.  
  24. bool myCmp(const Road &a, const Road &b)
  25. {
  26.     if(a.value < b.value)
  27.         return 1;
  28.     return 0;
  29. }
  30.  
  31. //node[2]=1 node[8]=,node[3]=1,共同的祖先,如果(3,8)加进去,则构成回路,不要
  32. //有点像并查集
  33. int Find_Set(int n)
  34. {
  35.     if(node[n] == -1)
  36.         return n;
  37.     return node[n] = Find_Set(node[n]);
  38. }
  39.  
  40. bool Merge(int s1, int s2)
  41. {
  42.     int r1 = Find_Set(s1);
  43.     int r2 = Find_Set(s2);
  44.     if(r1 == r2)//如果相等证明构成回路,则直接返回一个0,不要把顶点加进来(下一步是加进去的)
  45.         return 0;
  46.     if(r1 < r2)
  47.         node[r2] = r1;
  48.     else
  49.         node[r1] = r2;
  50.     return 1;
  51. }
  52.  
  53. int main()
  54. {
  55.     freopen("input.txt", "r", stdin);
  56.     //初始化全为-1
  57.     memset(node, -1, sizeof(node));
  58.     scanf("%d",&no);
  59.     scanf("%d",&line);
  60.     int i;
  61.     for(i=0; i<line; ++i)
  62.     {
  63.         cin >> road[i].c1 >> road[i].c2 >> road[i].value;
  64.     }
  65.     sort(road, road+line, myCmp);
  66.     int sum = 0, count = 0; // sum是MST的值,count是记录已使用的点数
  67.     for(i=0; i<line; ++i)
  68.     {
  69.         if(Merge(road[i].c1, road[i].c2))//如果返回的为0,则证明构成回路,不要加进
  70.         {
  71.             count ++;
  72.             sum += road[i].value;
  73.         }
  74.         if(count == no-1)//e=n-1已经连通,可以退出
  75.             break;
  76.     }
  77.     cout << sum << endl;
  78.     return 0;
  79. }
  80.  
  81.  
  82. /*
  83. input.txt:
  84. 9
  85. 14
  86. 1 2 4
  87. 1 8 8
  88. 2 3 8
  89. 2 8 11
  90. 3 4 7
  91. 3 6 4
  92. 3 9 2
  93. 4 5 9
  94. 4 6 14
  95. 5 6 10
  96. 6 7 2
  97. 7 8 1
  98. 7 9 6
  99. 8 9 7
  100. */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
普里姆算法(Prim's Algorithm)和克鲁斯卡尔算法Kruskal's Algorithm)都是用于解决最小生成树(Minimum Spanning Tree,MST)问题的经典算法。 最小生成树是一个连通图的生成树,它包含了图中所有顶点,并且具有最小的总权重。普里姆算法克鲁斯卡尔算法都可以用来找到图的最小生成树,但它们的思路和实现方式有所不同。 普里姆算法的思路是从一个起始顶点开始,逐步选择与当前生成树连接的权重最小的边,并将其加入到生成树中,直到生成树包含了图中所有的顶点。具体步骤如下: 1. 初始化一个空的生成树,将起始顶点加入生成树中。 2. 重复以下步骤,直到生成树包含了图中所有的顶点: - 选择与当前生成树连接的权重最小的边。 - 将该边连接的顶点加入生成树中。 克鲁斯卡尔算法则是基于边来构建最小生成树的。它首先将图中的所有边按照权重进行排序,然后逐个选择权重最小的边,并判断该边的两个顶点是否属于同一个连通分量(即是否会形成环)。如果不会形成环,则将该边加入到最小生成树中,直到最小生成树包含了图中所有的顶点。具体步骤如下: 1. 初始化一个空的最小生成树。 2. 将图中所有边按照权重进行排序。 3. 重复以下步骤,直到最小生成树包含了图中所有的顶点: - 选择权重最小的边。 - 判断该边的两个顶点是否属于同一个连通分量。 - 如果属于同一个连通分量,则选择下一条边。 - 如果不属于同一个连通分量,则将该边加入最小生成树中,并将两个顶点合并为一个连通分量。 这就是普里姆算法克鲁斯卡尔算法的基本思路和步骤。它们都可以有效地找到图的最小生成树,但在不同的应用场景下可能有不同的性能表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值