推荐:http://squirrelrao.iteye.com/blog/1044867

   http://www.cnblogs.com/xwdreamer/archive/2011/06/16/2296997.html

  http://blog.csdn.net/believejava/article/details/17414037

一、Prim算法:

Prim算法实现的是找出一个有权重连通图中的最小生成树,即:具有最小权重且连接到所有结点的树。(强调的是树,树是没有回路的)。

Prim算法是这样来做的:

首先以一个结点作为最小生成树的初始结点,然后以迭代的方式找出与最小生成树中各结点权重最小边,并加入到最小生成树中。加入之后如果产生回路则跳过这条边,选择下一个结点。当所有结点都加入到最小生成树中之后,就找出了连通图中的最小生成树了。

  1. /*
  2. prim 最小生成树算法
  3. 过程:prim算法将图分为两部分,假设原顶点集为V,将其分为S和V-S两部分,S为已经确定在最小生成树上的顶点,
  4. 开始时,将任意一个顶点加入到S,然后每次在V-S中寻找距离S中的点最近的点。作为下一个加入最小生成树上的点。
  5. 所有N个节点都加入到最小生成树中时,最小生成树构造完毕。
  6.  
  7. 实现:对于邻接矩阵构造的图,可以用low[N]保存每个顶点到已加入生成树中所有点的最小距离。
  8. 每次寻找这个距离最小的一个点加入最小生成树中。再根据这个点的距离更新其它未加入生成树中的点。
  9. 直到所有的点都加入到最小生成树中。
  10. */
  11.  
  12. // Eg:HDU 1102
  13.  
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <iostream>
  17. #define inf 1000000
  18. using namespace std;
  19.  
  20. int g[210][210];
  21. int low[210];
  22. int vis[210]; // 表示该点是否已经加入最小生成树中
  23. int n;
  24.  
  25. int prim() {
  26. for (int i=0; i<n; ++i) {
  27. low[i] = g[0][i];
  28. }
  29.  
  30. int ans = 0;
  31. memset(vis, 0, sizeof(vis));
  32. vis[0] = 1;
  33.  
  34. for (int i=1; i<n; ++i) { // 循环n-1次,找剩下的n-1个点。
  35. int k = -1, mindis = inf;
  36. for (int j=0; j<n; ++j) { // 循环找当前剩下的点中 距离最小生成树点集距离最短的点。
  37. if (!vis[j] && low[j] < mindis) {
  38. mindis = low[j];
  39. k = j;
  40. }
  41. }
  42.  
  43. if (k == -1) return -1;
  44. vis[k] = 1; // 加入最小生成树点集
  45. ans += mindis;
  46.  
  47. for (int j=0; j<n; ++j) { // 更新没加入最小生成树的点中 距离是否会缩短。
  48. /*if (!vis[j] && low[j] > low[k] + g[k][j]) {
  49. low[j] = low[k] + g[k][j];
  50. }*/
  51.  
  52. if (!vis[j] && low[j] > g[k][j]) { // 上面的if是错的。low数组存储的距离是当前点到生成树中所有点距离最小的的点。
  53. low[j] = g[k][j]; // 因为这个点加入最小生成树集合中,可以和其中任意一个点连一条边。
  54. }
  55. }
  56. }
  57. return ans;
  58. }
  59.  
  60. int main() {
  61. int q;
  62. while(cin >> n) {
  63. for (int i=0; i<n; ++i) {
  64. for (int j=0; j<n; ++j) {
  65. cin >> g[i][j];
  66. }
  67. }
  68.  
  69. cin >> q;
  70. for (int i=0; i<q; ++i) {
  71. int a, b;
  72. cin >> a >> b;
  73. a--, b--;
  74. g[a][b] = 0;
  75. g[b][a] = 0;
  76. }
  77.  
  78. int ans = prim();
  79. cout << ans << endl;
  80. }
  81. return 0;
  82. }

  

二、Kruskal算法:

Kruskal算法与Prim算法的不同之处在于,Kruskal在找最小生成树结点之前,需要对所有权重边做从小到大排序。将排序好的权重边依次加入到最小生成树中,如果加入时产生回路就跳过这条边,加入下一条边。当所有结点都加入到最小生成树中之后,就找出了最小生成树。

无疑,Kruskal算法在效率上要比Prim算法快,因为Kruskal只需要对权重边做一次排序,而Prim算法则需要做多次排序。尽管Prim算法每次做的算法涉及的权重边不一定会涵盖连通图中的所有边,但是随着所使用的排序算法的效率的提高,Kruskal算法和Prim算法之间的差异将会清晰的显性出来。

  1. /*
  2. 最小生成树 kruskal算法
  3. 过程:每次选取没有参与构造最小生成树并且加入之后不会构成回路的边中权值最小的一条
  4. 作为最小生成树的一条新边。直至选择了V-1条边。
  5. */
  6.  
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <iostream>
  10. #include <algorithm>
  11. #define maxn 2100
  12. using namespace std;
  13.  
  14. int fa[maxn], r[maxn];
  15.  
  16. void init(int n) {
  17. for (int i=1; i<=n; ++i) {
  18. fa[i] = i;
  19. r[i] = 1;
  20. }
  21. }
  22.  
  23. int find_fa(int v) { // 递归式路径压缩
  24. if (fa[v] != v) fa[v] = find_fa(fa[v]);
  25. return fa[v];
  26. }
  27.  
  28. /*int find_fa(int v) { // 非递归式路径压缩
  29. int k, j, r;
  30. r = v;
  31. while(r != fa[r])
  32. r = fa[r]; //找到根节点 记录在r上。
  33. k = v;
  34. while(k != r) {
  35. j = fa[k];
  36. fa[k] = r;
  37. k = j;
  38. }
  39. return r;
  40. }*/
  41.  
  42. /*void unin(int u, int v) { // 非按秩合并
  43. int fau = find_fa(u);
  44. int fav = find_fa(v);
  45. if (fau != fav)
  46. fa[fav] = fau;
  47. }*/
  48.  
  49. void unin(int u, int v) { // 按秩合并
  50. int fau = find_fa(u);
  51. int fav = find_fa(v);
  52. if (fau == fav) return;
  53.  
  54. if (r[u] < r[v]) fa[fau] = fav;
  55. else {
  56. if (r[u] == r[v])
  57. r[u]++;
  58. fa[fav] = fau;
  59. }
  60. }
  61.  
  62. struct Edge {
  63. int u, v, w;
  64. }edge[1000010];
  65.  
  66. bool cmp(Edge a, Edge b) {
  67. return a.w > b.w;
  68. }
  69.  
  70. int ans;
  71. int kruskal(int n, int m) { // 传入顶点个数n 和 边的个数m
  72. init(n);
  73. sort(edge, edge+m, cmp);
  74. ans = 0;
  75. int ret = 0; // 生成树的总权值
  76. int cnt = 0; // 已加入最小生成树的边的数量
  77.  
  78. for (int i=0; i<m; ++i) {
  79. if (find_fa(1) == find_fa(n)) return -1;
  80. int u = edge[i].u;
  81. int v = edge[i].v;
  82. if (find_fa(u) != find_fa(v)) {
  83. cnt++;
  84. ret += edge[i].w;
  85. unin(u, v);
  86. ans = edge[i].w;
  87. }
  88. if (cnt == n-1) return ret; // 已找到n-1条边,生成树构造完毕
  89. }
  90. return -1;
  91. }
  92.  
  93. int main() {
  94. int casee = 1;
  95. int t;
  96. cin >> t;
  97. while(t--) {
  98. int n, m;
  99. cin >> n >> m;
  100. for (int i=0; i<m; ++i) {
  101. cin >> edge[i].u >> edge[i].v >> edge[i].w;
  102. }
  103. kruskal(n, m);
  104. cout << "Scenario #" << casee++ << ":" << endl << ans << endl << endl;
  105. }
  106. return 0;
  107. }

  

关于时间复杂度:

prim:该算法的时间复杂度为O(n2)。与图中边数无关,该算法适合于稠密图。

kruskal:需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系,可以证明其时间复杂度为O(eloge)。适合稀疏图。

prim和kruskal比较的更多相关文章

  1. Prim和Kruskal最小生成树

    标题: Prim和Kruskal最小生成树时 限: 2000 ms内存限制: 15000 K总时限: 3000 ms描述: 给出一个矩阵,要求以矩阵方式单步输出生成过程.要求先输出Prim生成过程,再 ...

  2. 【图论】信手拈来的Prim,Kruskal和Dijkstra

    关于三个简单的图论算法 prim,dijkstra和kruskal三个图论的算法,初学者容易将他们搞混,所以放在一起了. prim和kruskal是最小生成树(MST)的算法,dijkstra是单源最 ...

  3. 图的最小生成树的理解和实现:Prim和Kruskal算法

    最小生成树 一个连通图的生成树是一个极小的连通子图,它含有图中所有的顶点,但只有足以构成一棵树的n-1条边.我们将构造连通网的最小代价生成树称为最小生成树(Minimum Cost Spanning ...

  4. 最小生成树(prim和kruskal)

    最小生成树(prim和kruskal) 最小生成树的最优子结构性质 设一个最小生成树是T.如果选出一个T中的一条边,分裂成的两个树T1,T2依然是它们的点集组成的最小生成树.这可以用反证法来证.反着来 ...

  5. HDU 3080 The plan of city rebuild(prim和kruskal)

    The plan of city rebuild Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java ...

  6. 最小生成树,Prim和Kruskal的原理与实现

    文章首先于微信公众号:小K算法,关注第一时间获取更新信息 1 新农村建设 大清都亡了,我们村还没有通网.为了响应国家的新农村建设的号召,村里也开始了网络工程的建设. 穷乡僻壤,人烟稀少,如何布局网线, ...

  7. 最小生成树MST算法(Prim、Kruskal)

    最小生成树MST(Minimum Spanning Tree) (1)概念 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边,所谓一个 ...

  8. Prim和Kruskal求最小生成树

    Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小 ...

  9. hdu_1875_畅通工程再续 prim和kruskal

    这个题是个典型的最小生成树的题目,但是刚开始怎么都过不了,后来发现两种写法都有疏忽,但是prim的到目前为止不懂为什么刚开始的不对,kruskal算法,并查集的初始条件从0开始写成从1开始了,所以已知 ...

  10. 图的最小生成树(Prim、Kruskal)

    理论: Prim: 基本思想:假设G=(V,E)是连通的,TE是G上最小生成树中边的集合.算法从U={u0}(u0∈V).TE={}开始.重复执行下列操作: 在所有u∈U,v∈V-U的边(u,v)∈E ...

随机推荐

  1. 使用git和gitlab进行协同开发流程

    一.基本概念 1.仓库(Repository) ①源仓库(线上版本库) 在项目的开始,项目的发起者构建起一个项目的最原始的仓库,称为origin. 源仓库的有两个作用: 1.汇总参与该项目的各个开发者 ...

  2. stm8s 时钟库函数选择内部RC初始化

    //本文选择16M内部RC震荡.分频为1 即系统时钟为16M void CLK_HSICmd(FunctionalState NewState) { /* Check the parameters * ...

  3. log4j2配置日志大小,个数等

    1:设置log输出文件 https://www.cnblogs.com/sa-dan/p/6837225.html <?xml version="1.0" encoding= ...

  4. [py]python中的==和is的区别

    is比较id id(a) == id(b) == id(c) a is d #false ==比较值 a==b #true 举个例子:a = 1 b = a c = 1 d = 1.0 这里有3个对象 ...

  5. ref out 区别

    1.使用ref型参数时,传入的参数必须先被初始化.对out而言,必须在方法中对其完成初始化. 2.使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字.以满足匹配. 3.out适 ...

  6. mysql慢日志

    mysql慢日志是用来记录执行时间比较长的sql工具(超过long_query_time的sql),这样对于跟踪有问题的sql很有帮助. 查看是否启用慢日志和相关信息 上面截图其中: log_slow ...

  7. 使用Vuejs编写单js组件

    1.引用方式 我们使用Vue进行普通页面开发却不使用webpack等技术时,定义组件可以只依赖单js文件进行开发 然后像正常引用js文件那样进行引用 <script src="../C ...

  8. mongodb-的副本集

    复制的重要性不再多说,其主要就是提供数据保护,数据高可用和灾难恢复. 复制是跨多个mongodb服务器分布和维护的方法.mongodb可以把数据从一个节点复制到其他节点并在修改时进行同步. mongo ...

  9. redis未授权访问漏洞总结

    Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 漏洞介绍: Redis 默认情况下,会绑定在 0.0.0.0 ...

  10. 使用4K显示器遇到的坑

    第一大坑:鼠标移动变慢,有强烈的滞后感 让人怀疑是不是系统因为要支持4K屏而变慢了,或者是鼠标坏了!甚至猜想是不是4K显示器的屏幕,因为分辨率太高,导致鼠标需要移动的点太多,因而耗时,产生了滞后感. ...