题目大意

给出一个无向图,求出最小生成树,如果该图不连通,则输出orz。

概念

对于一个无向图,要求选出一些边,使得图上的每一个节点互相连通,且边权和最小。选出的边与节点形成的子图必然是颗树,这棵树叫做最小生成树。

Prim算法

原理

最小生成树中,除根节点外,每一个节点作为一个to节点与它相邻的边的边权(以后简称最小相邻边权)必然是最小的。

实现方法

邻接表

像Dijkstra一样,用一个priority_queue维护已访问的边,使得堆顶的边的边权是最小的。每次循环给出一条边cur,如果cur->to节点不在树中,则cur的权值便是cur->to的最小相邻边权。于是将cur->to节点纳入树中并记录结果。然后,由to节点扩展与它相邻的边e(e->to也不在树内)。

邻接矩阵

对于稠密图,用邻接表的方式还要维护一个堆,时间太慢。所以定义LowLen[u]为u节点目前搜索到的作为一个to节点与它相邻的边的边权的最小值。每次关于树内边的个数的cnt循环,将堆顶出来一条边改为枚举每一个不在树内的节点,找出LowLen[u]最小的u,此时的LowLen[u]便是u最小相邻边权。于是将u纳入树中,记录结果,然后通过u刷新与它相邻的树外节点的LowLen。

  1. #include <cstdio>
  2. #include <queue>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <cmath>
  6. //#define test
  7. #define LOOP(a, b) for(int a=1;(a)<=(b);a++)
  8. using namespace std;
  9.  
  10. const int MAX_NODE = 5010, MAX_EDGE = 200010 * 2, INF = 0x3f3f3f3f;
  11.  
  12. struct Prim
  13. {
  14. struct Node;
  15. struct Edge;
  16.  
  17. struct Node
  18. {
  19. Edge *Head;
  20. int Id;
  21. bool Vis;
  22.  
  23. Node()
  24. {
  25. Head = NULL;
  26. Vis = false;
  27. Id = 0;
  28. }
  29. }_nodes[MAX_NODE];
  30. int _vCount;
  31. Node *Start;
  32.  
  33. struct Edge
  34. {
  35. Node *From, *To;
  36. Edge *Next;
  37. int Len, Id;
  38. bool InGraph;
  39.  
  40. Edge()
  41. {
  42. From = To = NULL;
  43. Next = NULL;
  44. Len = Id = 0;
  45. InGraph = false;
  46. }
  47.  
  48. bool operator <(const Edge a)const
  49. {
  50. return Len > a.Len;
  51. }
  52. }_edges[MAX_EDGE];
  53. int _eCount;
  54.  
  55. void Init(int vCount, int sId)
  56. {
  57. memset(_nodes, 0, sizeof(_nodes));
  58. memset(_edges, 0, sizeof(_edges));
  59. _vCount = vCount;
  60. _eCount = 0;
  61. Start = sId + _nodes;
  62. }
  63.  
  64. Edge *NewEdge()
  65. {
  66. return ++_eCount + _edges;
  67. }
  68.  
  69. void AddEdge(Node *from, Node *to, int len)
  70. {
  71. Edge *e = NewEdge();
  72. e->Id = _eCount;
  73. e->From = from;
  74. e->To = to;
  75. e->Len = len;
  76. e->Next = e->From->Head;
  77. e->From->Head = e;
  78. }
  79.  
  80. void Build(int uId, int vId, int len)
  81. {
  82. Node *u = uId + _nodes, *v = vId + _nodes;
  83. u->Id = uId;
  84. v->Id = vId;
  85. AddEdge(u, v, len);
  86. AddEdge(v, u, len);
  87. }
  88.  
  89. int Proceed()
  90. {
  91. int ans = 0, cnt = 0;
  92. priority_queue<Edge> q;
  93. Start->Vis = true;//易忘点
  94. cnt++;//易忘点
  95. for (Edge *e = Start->Head; e; e = e->Next)
  96. q.push(*e);
  97. while (!q.empty() && cnt<_vCount)//易忘点:小于
  98. {
  99. Edge temp = q.top();
  100. q.pop();
  101. Edge *cur = temp.Id + _edges;
  102. if (cur->To->Vis)
  103. continue;
  104. cur->To->Vis = true;
  105. cur->InGraph = true;
  106. ans += cur->Len;
  107. cnt++;
  108. for (Edge *e = cur->To->Head; e; e = e->Next)
  109. if (!e->To->Vis)
  110. q.push(*e);
  111. }
  112. return cnt == _vCount ? ans : -1;
  113. }
  114. }g;
  115.  
  116. struct PrimMatrix
  117. {
  118. int Len[MAX_NODE][MAX_NODE];
  119. bool InTree[MAX_NODE];
  120. int LowLen[MAX_NODE];
  121. int _vCount;
  122.  
  123. void Init(int vCount)
  124. {
  125. memset(Len, INF, sizeof(Len));
  126. _vCount = vCount;
  127. }
  128.  
  129. void Build(int u, int v, int dist)
  130. {
  131. Len[u][v] = Len[v][u] = min(Len[u][v], dist);
  132. }
  133.  
  134. int Proceed()
  135. {
  136. int cnt = 1, ans = 0;
  137. memset(InTree, false, sizeof(InTree));
  138. memset(LowLen, INF, sizeof(LowLen));
  139. InTree[1] = true;//易忘点
  140. LOOP(v, _vCount)
  141. LowLen[v] = Len[1][v];
  142. LOOP(i, _vCount)
  143. {
  144. int u, lowLen = INF;
  145. LOOP(j, _vCount)
  146. {
  147. if (!InTree[j] && LowLen[j] < lowLen)
  148. {
  149. lowLen = LowLen[j];
  150. u = j;
  151. }
  152. }
  153. if (lowLen == INF)
  154. break;
  155. cnt++;
  156. ans += lowLen;
  157. InTree[u] = true;
  158. LOOP(v, _vCount)//注意从此往后就不用lowLen了。lowLen就是为了确定u用的。
  159. if (!InTree[v] && Len[u][v] < LowLen[v])
  160. LowLen[v] = Len[u][v];
  161. }
  162. return cnt == _vCount ? ans : -1;
  163. }
  164. }g1;
  165.  
  166. int main()
  167.  
  168. {
  169. int totNode, totEdge, uId, vId, len;
  170. scanf("%d%d", &totNode, &totEdge);
  171. g1.Init(totNode);
  172. while (totEdge--)
  173. {
  174. scanf("%d%d%d", &uId, &vId, &len);
  175. g1.Build(uId, vId, len);
  176. }
  177. int ans = g1.Proceed();
  178. if (ans == -1)
  179. printf("orz\n");
  180. else
  181. printf("%d\n", ans);
  182. return 0;
  183. }

  

luogu3366 【模板】 最小生成树 Prim的更多相关文章

  1. 模板——最小生成树prim算法&&向前星理解

    通过最小生成树(prim)和最短路径优化引出的向前星存图,时至今日才彻底明白了.. head[i]存储的是父节点为i引出的最后一条边的编号, next负责把head[i]也就是i作为父节点的所有边连接 ...

  2. poj1861 最小生成树 prim &amp; kruskal

    // poj1861 最小生成树 prim & kruskal // // 一个水题,为的仅仅是回味一下模板.日后好有个照顾不是 #include <cstdio> #includ ...

  3. 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。

    //归并排序递归方法实现 #include <iostream> #include <cstdio> using namespace std; #define maxn 100 ...

  4. 邻接矩阵c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)

    matrix.c #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include < ...

  5. 最小生成树Prim算法(邻接矩阵和邻接表)

    最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...

  6. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  7. 最小生成树Prim

    首先解释什么是最小生成树,最小生成树是指在一张图中找出一棵树,任意两点的距离已经是最短的了. 算法要点: 1.用book数组存放访问过的节点. 2.用dis数组保存对应下标的点到树的最近距离,这里要注 ...

  8. 最小生成树—prim算法

    最小生成树prim算法实现 所谓生成树,就是n个点之间连成n-1条边的图形.而最小生成树,就是权值(两点间直线的值)之和的最小值. 首先,要用二维数组记录点和权值.如上图所示无向图: int map[ ...

  9. 最小生成树Prim算法和Kruskal算法

    Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...

  10. 最小生成树 Prim Kruskal

    layout: post title: 最小生成树 Prim Kruskal date: 2017-04-29 tag: 数据结构和算法 --- 目录 TOC {:toc} 最小生成树Minimum ...

随机推荐

  1. B - Double Cola

    Problem description Sheldon, Leonard, Penny, Rajesh and Howard are in the queue for a "Double C ...

  2. c# ado.net eftity framework 返回多表查询结果

    public static IQueryable GetWeiXinTuWenList() { using (var Model = new Model.WeiXinEntities()) { var ...

  3. 用js制作一个计算器

    使用js制作计算器 <!doctype html> <html lang="en"> <head> <meta charset=" ...

  4. 微信公众号API使用总结

    官网:    https://mp.weixin.qq.com/ API:          http://mp.weixin.qq.com/wiki/home/index.html 接口调试工具:h ...

  5. git与pycharm结合使用

    一.配置pycharm 在pycharm中选择file-->setting,在弹出的窗口中选择version control,选择git,配置git的路径 将当前项目关闭 在弹出的窗口中选择ch ...

  6. BZOJ 3510: 首都 LCT + multiset维护子树信息 + 树的重心

    Code: #include<bits/stdc++.h> #define maxn 200000 #define inf 1000000000 using namespace std; ...

  7. BZOJ 4327: JSOI2012 玄武密码 后缀自动机

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) # ...

  8. PAT_A1072#Gas Station

    Source: PAT A1072 Gas Station (30 分) Description: A gas station has to be built at such a location t ...

  9. python PIL图像处理-框选

    框选图中位置 代码 from PIL import Image,ImageDraw,ImageFont,ImageFilter import random #--------------------- ...

  10. 接口测试与Postman

    阅读目录 1.接口测试简介 1.1 什么是接口测试  1.2 接口测试的必要性 1.3 接口测试流程 1.4 接口文档 1.5 接口测试用例设计 1.6 接口测试用例模板 2.Postman 2.1 ...