10.5.1 最小生成树及其性质

最小生成树是无向图中的一棵树,涵盖图G的所有顶点,并且边之和最小
最小生成树的三个性质:
1、是树,边数=顶点数-1
2、对于给定的图,最小生成树可以不唯一,但是边权值和是唯一的
3、最小生成树的根节点可以是任何一个节点,但是题目为了方便输出,一般会用题目给的节点作为根节点
P算法和K算法都是采用贪心法求最小生成树,只是贪心的策略不一样

10.5.2 prim算法

P算法与求最短路径的D算法思想几乎完全相同
区别是P算法中d[i]指的是点i距离集合S的距离
D算法中d[i]指的是点i距离起点S的距离
复杂度是O(V²),可以进行堆优化
尽量在图的顶点数目较少,而边数较多的时候使用prim算法

10.5.3 kruskal算法

采用边贪心的策略
时间复杂度主要来自对边的排序,为O(ElogE),所以适合顶点较多,边较少的情况

习题

注意P算法适用于边较多的情况,K算法适用于顶点较多的情况
问题 A: 还是畅通工程
问题描述: 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

  • 输入
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。
当N为0时,输入结束,该用例不被处理。```- 输出```cpp
对每个测试用例,在1行里输出最小的公路总长度。
  • 样例输入
8
1 2 42
1 3 68
1 4 35
1 5 1
1 6 70
1 7 25
1 8 79
2 3 59
2 4 63
2 5 65
2 6 6
2 7 46
2 8 82
3 4 28
3 5 62
3 6 92
3 7 96
3 8 43
4 5 28
4 6 37
4 7 92
4 8 5
5 6 3
5 7 54
5 8 93
6 7 83
6 8 22
7 8 17
0
  • 样例输出
82

这题使用P算法:
因为是多点测试,注意要初始化所有的变量

#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxv = 110;//表示最多100个村庄
const int INF = 1000000000;//无穷大
int n, m, G[maxv][maxv];
int d[maxv];
int vis[maxv];
int prim()
{fill(d, d + maxv, INF);fill(vis, vis + maxv, 0);d[1] = 0;int ans = 0;//首先找到距离集合S最小的点u以及距离d[u]for (int i = 1; i <=n; i++){int u = -1,MIN = INF;for (int j = 1; j <= n; j++){if (vis[j] == 0 && d[j] < MIN){u = j;MIN = d[j];}}if (u == -1) return -1;vis[u] = 1;ans += d[u];for (int v = 1; v <= n; v++){if (vis[v] == 0 && G[u][v] != INF && G[u][v] < d[v])d[v] = G[u][v];}}return ans;}
int main()
{int u, v, w;while (scanf("%d", &n) != EOF){if (n == 0)break;else{fill(G[0], G[0] + maxv * maxv, INF);int temp = n * (n - 1) / 2;for (int i = 1; i <= temp; i++){scanf("%d%d%d", &u, &v, &w);G[u][v] = G[v][u] = w;}int ans = prim();printf("%d ", ans);}}return 0;
}

问题B:雀斑
问题描述:在迪克·范戴克 (Dick Van Dyke) 节目的一集中,小里奇 (Richie) 将父亲背上的雀斑连接起来,形成了自由钟的照片。唉,其中一个雀斑原来是疤痕,所以他的里普利的订婚失败了。
将 Dick 的背部视为在不同 (x,y) 位置有雀斑的平面。你的工作是告诉 Richie 如何连接点,以尽量减少使用的墨水量。里奇通过在对之间画直线来连接点,可能会在线之间提起笔。当 Richie 完成后,必须有一系列从任何雀斑到任何其他雀斑的连接线。

  • 输入
第一行包含 0 < n <= 100,即 Dick 背上雀斑的数量。对于每个雀斑,后面跟着一条线;以下每一行包含两个实数,表示雀斑的 (x,y) 坐标。
  • 输出
您的程序将一个实数打印到两个小数位:可以连接所有雀斑的墨水线的最小总长度。
  • 样例输入
3
2723.62 7940.81
8242.67 11395.00
4935.54 6761.32
9
10519.52 11593.66
12102.35 2453.15
7235.61 10010.83
211.13 4283.23
5135.06 1287.85
2337.48 2075.61
6279.72 13928.13
65.79 1677.86
5324.26 125.56
0
  • 样例输出
8199.56
32713.73

这题同样是稠密图,所以使用P算法:

#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxv = 110;//表示最多100个村庄
const double INF = 1000000000;//无穷大
int n, m;
double G[maxv][maxv];
int flag[maxv][maxv];
double x[maxv], y[maxv];
double d[maxv];
int vis[maxv];
double prim()
{fill(d, d + maxv, INF);fill(vis, vis + maxv, 0);d[1] = 0;double ans = 0;//首先找到距离集合S最小的点u以及距离d[u]for (int i = 1; i <=n; i++){int u = -1,MIN = INF;for (int j = 1; j <= n; j++){if (vis[j] == 0 && d[j] < MIN){u = j;MIN = d[j];}}if (u == -1) return -1;vis[u] = 1;ans += d[u];//printf("!!!\n");for (int v = 1; v <= n; v++){if (vis[v] == 0 && G[u][v] != INF && G[u][v] < d[v])d[v] = G[u][v];}}return ans;}
int main()
{int u, v, w;while (scanf("%d", &n) != EOF){if (n == 0)break;else{fill(G[0], G[0] + maxv * maxv, INF);fill(flag[0], flag[0] + maxv * maxv, 0.0);for (int i = 1; i <= n; i++){scanf("%lf%lf",&x[i],&y[i]);//注意double类型输入要用%lf}for (int i = 1; i <= n; i++){for(int j=1;j<=n;j++){ if (flag[i][j]==0){G[i][j] = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));flag[i][j] = 1;//printf("%f\n",G[i][j]);}}}double ans = prim();printf("%.2f\n", ans);}        }   return 0;
}

问题 C: 畅通工程
问题描述:省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。

  • 输入
测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M (N, M < =100 );随后的 N 行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。
  • 输出
对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。
  • 样例输入
3 4
1 2 1
2 3 2
3 4 3
2 4
1 2 1
3 4 2
0 5
  • 样例输出
6
?

不能保证畅通即ans=-1,这题用K算法更加直观一些。

#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxv = 110;//表示最多100个村庄
const int INF = 1000000000;//无穷大
int n, m, G[maxv][maxv];
int d[maxv];
int vis[maxv];
int prim()
{fill(d, d + maxv, INF);fill(vis, vis + maxv, 0);d[1] = 0;int ans = 0;//首先找到距离集合S最小的点u以及距离d[u]for (int i = 1; i <= m; i++){int u = -1, MIN = INF;for (int j = 1; j <= m; j++){if (vis[j] == 0 && d[j] < MIN){u = j;MIN = d[j];}}if (u == -1) return -1;vis[u] = 1;ans += d[u];for (int v = 1; v <= m; v++){if (vis[v] == 0 && G[u][v] != INF && G[u][v] < d[v])d[v] = G[u][v];}}return ans;}
int main()
{int u, v, w;while (scanf("%d", &n) != EOF){if (n == 0){break;}            else{scanf("%d",&m);//村庄数目mfill(G[0], G[0] + maxv * maxv, INF);for (int i = 1; i <= n; i++){scanf("%d%d%d", &u, &v, &w);G[u][v] = G[v][u] = w;}int ans = prim();if (ans != -1)printf("%d\n", ans);elseprintf("?\n");}}return 0;
}

问题 D: 继续畅通工程
问题描述:省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。

  • 输入
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
  • 输出
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
  • 样例输入
4
1 2 1 1
1 3 6 0
1 4 2 1
2 3 3 0
2 4 5 0
3 4 4 0
3
1 2 1 1
2 3 2 1
1 3 1 0
0
  • 样例输出
3
0

这题用K算法比较直观,一定要注意下标!!,一个是sort函数的下标,一个是循环的下标
方法1

#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxv = 110;//表示最多100个村庄
const int maxe = 10010;
struct edge {int u;int v;int cost;int flag;//=1表示已建,=0表示未建
}E[maxe];
bool cmp(edge a, edge b)
{return a.cost < b.cost;
}
int father[maxv];
int findFather(int x)
{int a = x;while (x != father[x]){x = father[x];}int z = a;while (a != father[a]){father[z] = x;a = father[a];z = a;}return x;
}
int kruskal(int n, int m)
{int ans = 0, Num_Edge = 0;for (int i = 1; i <=n; i++)//n个点{father[i] = i;}//初始化//排序从低向高  sort(E+1, E +1+ m, cmp);for (int i = 1; i <= m; i++)//m条边{int faU = findFather(E[i].u);int faV = findFather(E[i].v);if (faU != faV){father[faU] = faV;ans += E[i].cost;Num_Edge++;if (Num_Edge == n - 1)break;}}if (Num_Edge != n-1) return -1;else return ans;
}int main()
{int n;int m;while (scanf("%d", &n) != EOF){if (n == 0)break;else{m = n * (n - 1) / 2;for (int i = 1; i <=m ; i++){scanf("%d%d%d%d", &E[i].u, &E[i].v, &E[i].cost, &E[i].flag);if (E[i].flag == 1)E[i].cost = 0;}}int ans = kruskal(n, m);printf("%d\n",ans);} return 0;
}

方法2:
还是方法一简单一点,但是不好想。

#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxv = 110;//表示最多100个村庄
const int maxe = 10010;
struct edge {int u;int v;int cost;int flag;//=1表示已建,=0表示未建
}E[maxe];
bool cmp(edge a, edge b)
{return a.cost < b.cost;
}
int father[maxv];
int findFather(int x)
{int a = x;while (x != father[x]){x = father[x];}int z = a;while (a != father[a]){father[z] = x;a = father[a];z = a;}return x;
}
int kruskal(int n, int m)
{int ans = 0, Num_Edge = 0;for (int i = 1; i <=n; i++)//n个点{father[i] = i;}//初始化//首先让flag=1的点连通起来for (int i = 1; i <= m; i++)//m条边{if (E[i].flag == 1){int faU = findFather(E[i].u);int faV = findFather(E[i].v);if (faU != faV){father[faU] = faV;Num_Edge++;}}}sort(E+1, E +1+ m, cmp);for (int i = 1; i <= m; i++)//m条边{int faU = findFather(E[i].u);int faV = findFather(E[i].v);if (faU != faV){father[faU] = faV;ans += E[i].cost;Num_Edge++;if (Num_Edge == n - 1)break;}}if (Num_Edge != n-1) return -1;else return ans;
}int main()
{int n;int m;while (scanf("%d", &n) != EOF){if (n == 0)break;else{m = n * (n - 1) / 2;for (int i = 1; i <=m ; i++){scanf("%d%d%d%d", &E[i].u, &E[i].v, &E[i].cost, &E[i].flag);}}int ans = kruskal(n, m);printf("%d\n",ans);} return 0;
}

问题 E: Jungle Roads
问题描述:热带岛屿拉格里山的长老有问题。几年前,大量外援资金被用于修建村庄之间的额外道路。但是丛林无情地超越道路,因此大型道路网络的维护成本太高。长老议会必须选择停止维护一些道路。左上方的地图显示了所有正在使用的道路以及每月维护这些道路的成本(以 aacms 为单位)。当然,即使路线不像以前那么短,也需要通过某种方式在维护的道路上到达所有村庄。首席长老想告诉长老委员会,他们每个月可以在 aacms 上花费的最少金额来维护连接所有村庄的道路。在上面的地图中,村庄被标记为 A 到 I。右边的地图显示了可以最便宜地维护的道路,每月 216 aacms。你的任务是编写一个程序来解决这些问题。

  • 输入
输入由1到100个数据集组成,最后一行只包含0。 每个数据集以一行开始,只包含一个数字n,它是村庄的数量,1 < n < 27,村庄被标记字母表的前 n 个字母大写。每个数据集都由 n-1 行完成,这些行以字母顺序以村庄标签开头。最后一个村庄没有线路。一个村庄的每条线都以村庄标签开始,然后是从这个村庄到字母表中带有标签的村庄的道路数量 k。如果 k 大于 0,则该行继续包含 k 条道路中每条道路的数据。每条道路的数据是道路另一端的村庄标签,然后是道路的每月维护成本(以 aacms 为单位)。维护成本将是小于 100 的正整数。行中的所有数据字段都由单个空格分隔。公路网将始终允许在所有村庄之间通行。该网络的道路永远不会超过 75 条。没有一个村庄有超过 15 条通往其他村庄的道路(字母表中的之前或之后)。在下面的示例输入中,第一个数据集与上面的地图一致。
  • 输出
每个数据集的每行输出一个整数:维护连接所有村庄的道路系统的每月最低成本(以 aacms 为单位)。警告:检查每组可能的道路的蛮力解决方案不会在一分钟的时间限制内完成。
  • 样例输入
3
A 1 B 42
B 1 C 87
6
A 2 B 13 E 55
B 1 C 1
C 1 D 20
D 1 E 4
E 1 F 76
0
  • 样例输出
129
114

这题我改了一个小时!发现是输入输出的错误!
还有要注意结构体数组E的大小取决于边的个数,其他没什么啦

#define _CRT_SECURE_NO_WARNINGS 1
#include <cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxv = 30;
const int INF = 1000000000;
struct edge {int u;int v;int cost;
}E[900];
int n, m, k;
bool cmp(edge a, edge b)
{   return a.cost < b.cost;
}
int father[30];
int findFather(int x)
{int a = x;while (x != father[x]){x = father[x];}int z = a;while (a != father[a]){father[z] = x;a = father[a];z = a;        }return x;
}
int kruskal()
{int ans = 0, Num_Edge = 0;for (int i = 1; i <=n; i++)//n个点{father[i] = i;}//初始化sort(E, E+m, cmp);for (int i = 0; i < m; i++)//m条边{int faU = findFather(E[i].u);int faV = findFather(E[i].v);if (faU != faV){father[faU] = faV;ans += E[i].cost;Num_Edge++;if (Num_Edge == n - 1)break;}}if (Num_Edge != n-1) return -1;else return ans;
}int main()
{   char u[3], v[3];int w;while (scanf("%d", &n) != EOF){        if (n == 0)break;m = 0;for (int i = 1; i <= n - 1; i++)//一共n-1个地点{scanf("%s %d",u,&k);              while(k--){scanf("%s%d", v, &w);              E[m].u = u[0] - 'A' + 1;E[m].v = v[0] - 'A' + 1;E[m].cost = w;                     m++;}}int ans = kruskal();printf("%d\n", ans);     }   return 0;
}

《算法笔记》10.5小节——图算法专题->最小生成树相关推荐

  1. 算法笔记习题 7-1小节

    算法笔记@Ada_Lake 算法笔记代码保留地~~~ 7.1小节--提高篇->数据结构专题->栈的应用 首先讲了一下栈的定义.即栈就通俗而言即先进先出.每个栈都有一个栈顶指针来指向栈的最上 ...

  2. 算法笔记习题 2-9小节

    算法笔记@Ada_Lake 算法笔记代码保留地~~~ 2.9小节--C/C++快速入门->补充 有关cin 和 cout cout 中控制 double型 的精确度 - 1. 加入#includ ...

  3. 【算法笔记5.6小节 -大整数运算 】问题 C: 浮点数加法

    题目描述 求2个浮点数相加的和 题目中输入输出中出现浮点数都有如下的形式: P1P2...Pi.Q1Q2...Qj 对于整数部分,P1P2...Pi是一个非负整数 对于小数部分,Qj不等于0 输入 对 ...

  4. 【尚硅谷】Java数据结构与算法笔记10 - 树结构的基础部分

    文章目录 一.二叉树 1.1 为什么需要树结构 1.1.1 数组存储方式的分析 1.1.2 链式存储方式的分析 1.1.3 树存储方式的分析 1.2 树示意图 1.3 二叉树的概念 1.4 二叉树 - ...

  5. codeup墓地目录(算法笔记习题刷题笔记)

    在线codeup contest 地址:http://codeup.cn/contest.php Contest100000575 - <算法笔记>3.1小节--入门模拟->简单模拟 ...

  6. javascript进制转换_《算法笔记》3.5小节——入门模拟-gt;进制转换

    @[TOC] # Contest100000579 - <算法笔记>3.5小节--入门模拟->进制转换 ## 例题 ### PATB1022 PTA | 程序设计类实验辅助教学平台 ...

  7. Contest100000581 - 《算法笔记》4.1小节——算法初步-排序

    文章目录 Contest100000581 - <算法笔记>4.1小节--算法初步->排序 1.讲解 4.1 .1 选择排序 4.1.2 插入排序 4.1.3 排序题与sort()函 ...

  8. 程序员的算法课(20)-常用的图算法:最小生成树(MST)

    一.图的生成树和最小生成树 生成树(SpanningTree):如果一个图的子图是一个包含图所有节点的树,那这个子图就称为生成树.图的生成树不惟一.从不同的顶点出发进行遍历,可以得到不同的生成树.专业 ...

  9. 《算法笔记》2.3小节——C/C++快速入门-选择结构

    <算法笔记>2.3小节--C/C++快速入门->选择结构 Contest100000567 - <算法笔记>2.3小节--C/C++快速入门->选择结构 Conte ...

最新文章

  1. Oracle 中定位重要(消耗资源多)的SQL
  2. ESP8266 问题
  3. 数据中心虚拟化的8大好处
  4. Eclipse中启动tomcat报错:A child container failed during start
  5. 7个Python特殊技巧,助力你的数据分析工作之路
  6. java range(10)_Java 中的十个 ” 单行代码编程 ” ( OneLiner )
  7. BLE简介和Android BLE编程
  8. lstm数学推导_如何在训练LSTM的同时训练词向量?
  9. 前端开发 表单标签 完成一个简单登陆的效果 0228
  10. 数据分析-信用卡反欺诈模型
  11. LuatOS之LVGL字体篇
  12. 空手套白狼案例,18个月零成本开了 3 家健身房,分红400多万!
  13. ubuntu linux卸载软件命令,ubuntu安装和卸载软件命令
  14. linux修复fat文件系统,如何修复损坏的FAT32文件系统
  15. 免费手机上网的方法,比GPRS网速快很多(好东西与大家分亨)
  16. 软件测试人员如何持续提升自己的技术水平?从以下几点做起
  17. tomcat配置用户权限
  18. 三台服务器同时服务一个网站,三台服务器同时热备
  19. 云联惠案到底说明了什么?
  20. [CF4D]Mysterious Present

热门文章

  1. SPI器件的菊链配置
  2. nvidia xavier平台无PD控制器USB接口调试
  3. 企业级Docker容器镜像仓库Harbor的搭建
  4. JRebel-JVMTI [FATAL] Please make sure that ‘C:\Users\\AppData\Roaming\JetBrains\IntelliJIdea2020.
  5. MAR位数反应存储单元的个数 MDR位数=存储字长
  6. c语言sdk,C/C++ SDK
  7. Deep Learning on Graphs: A Survey
  8. java音频剪切_Java使用IO流实现音频的剪切和拼接
  9. 从最新的技术趋势看前端的未来
  10. html学习笔记-用代码画皮卡丘