图论——最小生成树

ops/2025/2/7 12:21:55/

最小生成树
给定一个无向图,在图中选择若干条边把图的所有节点连起来。要求边长之和最小。在图论中,叫做求最小生成树。
prim算法
prim 算法采用的是一种贪心的策略。
每次将离连通部分的最近的点和点对应的边加入的连通部分,连通部分逐渐扩大,最后将整个图连通起来,并且边长之和最小。

prim算法的贪心策略为什么是正确的?

当我们循环到某一部中,当前的连通块为图中绿色虚线内部分,离连通部分的最近的点和点对应的边如下图所示。
在这里插入图片描述
假设最小生成树中不包含这条边,那么为了最后保证联通,当前该点一定会通过其他路径与该连通块连起来,假设通过下图中红色路径。
在这里插入图片描述
红色路径中一定存在下图中橙色两个点,两点间存在一条边,因为灰色两点间边长一定不大于橙色两点间边长,否则一开始我们选择出的就不是灰色的这个点,所以我们如果把橙色两点间的边删掉,换做灰色两个点的连接,同样可以保持联通,并且一定不会得到更差的结果,也正因此肯证明prim算法贪心策略的正确性,每次将离连通部分的最近的点和点对应的边加入的连通部分。

在这里插入图片描述
kruskal算法
将所有边按照边权升序排序,枚举每条边 (a,b),如果这两个点不连通则把这条边加入最小生成树。

kruskal算法的正确性证明

如下图所示,绿色部分分别是两个连通块,当我们枚举到某一步时,存在一条边可以联通这两个连通块。
在这里插入图片描述
我们假设最小生成树中不包含这一条边,那么为了保证这两个连通块最后能够联通,那么这两个点最后肯定会通过其他路径连起来,假设通过下图中红色路径相连。
在这里插入图片描述
在该红色路线中,一定存在橙色和蓝色点对之间的距离不小于灰色点对之间的距离,因为在我们枚举到灰色点对时,橙色点对和蓝色点对之间还没联通,并且此时我们没有选择这两条边。所以该我们把灰色点对之间的边去替换掉橙色点对或者蓝色点对一定可以得到不差于当前的答案,也正因此我们把灰色点对联通是最优的。
在这里插入图片描述

acwing1140.最短网络

最短路算法裸题

#include <iostream>
#include <cstring>
using namespace std;
const int N = 110;
int n;
int g[N][N];
int dist[N];
bool st[N];
int prim()
{int res = 0;memset(dist, 0x3f, sizeof dist);dist[1] = 0;for (int i = 1; i <= n; i ++ ){int t = -1;for (int j = 1; j <= n; j ++ ){if (!st[j] && (t == -1 || (dist[t] > dist[j])))t = j;}st[t] = 1;res += dist[t];for (int j = 1; j <= n; j ++ )dist[j] = min(dist[j], g[t][j]);}return res;
}
int main()
{cin >> n;for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )cin >> g[i][j];int res = prim();cout << res;return 0;
}

acwing1141.局域网

我们将除去一些连线,使得网络中没有回路且不影响连通性(即如果之前某两个点是连通的,去完之后也必须是连通的),所以在我们去掉回路之后得到的是一个生成森林,在前面我们证明了kruskal算法求出一个最小生成树的结果一定是最优的,我们可以用相同的方法证明kruskal只进行到一半,求出的最小生成森林也是最优的。另外本题要求我们求的是需要删除的边长度最大值,那么我们在枚举边时只需要每次将不需要的边的长度加到答案里便可。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 110, M = 210;
struct Edge{int a, b, w;bool operator< (const Edge &t){return w < t.w;}
}e[M];
int fa[N];
int n, m;
int find(int a)
{return fa[a] == a ? a : fa[a] = find(fa[a]);
}
int main()
{cin >> n >> m;for (int i = 1; i <= m; i ++ ){int a, b, w;cin >> a >> b >> w;e[i] = {a, b, w};}for (int i = 1; i <= n; i ++ ) fa[i] = i;int res = 0;sort(e + 1, e + m + 1);for (int i = 1; i <= m; i ++ ){int a = e[i].a, b = e[i].b, w = e[i].w;if (find(a) != find(b)) fa[fa[a]] = b;else res += w;}cout << res;return 0;
}

acwing1142.繁忙的都市

1.改造的那些道路能够把所有的交叉路口直接或间接的连通起来。
2.在满足要求1的情况下,改造的道路尽量少。
3.在满足要求1、2的情况下,改造的那些道路中分值最大值尽量小。

首先很显然,为了将所有的边都连通起来,我们改造的道路数为n-1,即一棵生成树,另外本题要求道路中分值最大值尽量小,即求最小瓶颈生成树,而一般的最小生成树问题要求的时边权之和最小。我们可以证明一颗最小生成树一定是最小瓶颈生成树,证明方式和我们一开始最小生成树的证明相同,所以我们可以直接用最短路算法来做,枚举到的长度最长的边就是答案。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 310, M = 8010;
struct Edge{int a, b, w;bool operator< (const Edge &t) const{return w < t.w;}
}e[M];
int fa[N];
int n, m;
int find(int a)
{return fa[a] == a ? a : fa[a] = find(fa[a]);
}
int main()
{cin >> n >> m;for (int i = 1; i <= n; i ++ )fa[i] = i;for (int i = 1; i <= m; i ++ ){int a, b, c;cin >> a >> b >> c;e[i] = {a, b, c};}int res = 0;sort(e + 1, e + m + 1);for (int i = 1; i <= m; i ++ ){int a = find(e[i].a), b = find(e[i].b), w = e[i].w;if (a != b){fa[a] = b;res = w;}}cout << n - 1 << " " << res;return 0;
}

acwing1143.联络员

本题图中存在一些固定的边,要求我们增加一些新的边来让节点之间联通。

我们可以利用Kruskal,算法,思考一下,既然第1类边是必须选择的,那我们在读入的时候就直接把所有第1类边的权值加到我们的总边权中,并将它们统计到判断图是否连通的并查集里,然后照常做Kruskal就行。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2010, M = 10010;
struct Edge{int a, b, w;bool operator< (const Edge &t) const{return w < t.w;}
}e[M];
int fa[N];
int n, m;
int find(int a)
{return fa[a] == a ? a : fa[a] = find(fa[a]);
}
int main()
{cin >> n >> m;int k = 0;for (int i = 1; i <= n; i ++ )fa[i] = i;int res = 0;while (m -- ){int a, b, w, type;cin >> type >> a >> b >> w;if (type == 1){res += w;fa[find(a)] = find(b);}else e[++ k] = {a, b, w};}sort(e + 1, e + k + 1);for (int i = 1; i <= k; i ++ ){int a = find(e[i].a), b = find(e[i].b), w = e[i].w;if (a != b){res += w;fa[a] = b;}}cout << res;return 0;
}

acwing1144.连接格点

本题和上一题的核心思想是完全一样的,只不过本题涉及到了网格图和二维转一维,数据处理会稍微麻烦一些。

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010, M = N * N * 2, K = N * N;
int g[N][N];
int fa[N];
struct Edge{int a, b, w;bool operator< (const Edge &t) const{return w < t.w;}
}e[M];
int n, m;
int cnt = 0;
int find(int a)
{fa[a] == a ? a : fa[a] = find(fa[a]);
}
void get_edges()
{int dx[] = {0, -1, 0, 1}, dy[] = {-1, 0, 1, 0}, dw[] = {2, 1, 2, 1};for (int i = 1; i <= n; i ++ ){for (int j = 1; j <= m; j ++ ){for (int u = 2; u <= 3; u ++ ){int x = i + dx[u], y = j + dy[u];if (x == n + 1 || y == m + 1) continue;int a = g[i][j], b = g[x][y];e[++ cnt] = {a, b, dw[u]};}}}
}
int main()
{cin >> n >> m;int x1, y1, x2, y2;for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )g[i][j] = ++ cnt;cnt = 0;get_edges();for (int i = 1; i <= n * m; i ++ )fa[i] = i;while (cin >> x1 >> y1 >> x2 >> y2){int a = g[x1][y1], b= g[x2][y2];a = find(a), b = find(b);fa[a] = b;}int res = 0;sort(e + 1, e + cnt + 1);for (int i = 1; i <= cnt; i ++ ){int a = find(e[i].a), b = find(e[i].b), w = e[i].w;if (a != b){fa[a] = b;res += w;}}cout << res;return 0;
}

最小生成树扩展应用


http://www.ppmy.cn/ops/156433.html

相关文章

python学opencv|读取图像(五十三)原理探索:使用cv.matchTemplate()函数实现最佳图像匹配

【1】引言 前序学习进程中&#xff0c;已经探索了使用cv.matchTemplate()函数实现最佳图像匹配的技巧&#xff0c;并且成功对两个目标进行了匹配。 相关文章链接为&#xff1a;python学opencv|读取图像&#xff08;五十二&#xff09;使用cv.matchTemplate()函数实现最佳图像…

分布式光伏监控解决方案-并网柜保护装置

一、并网柜防孤岛保护 继电保护及安全自动装置 根据《光伏发电站接入电力系统的技术规定》GB/T 19964-2012的相关要求&#xff0c;光伏发电站应配置独立的防孤岛保护装置&#xff0c;动作时间应不大于2s。防孤岛保护还应与电网侧线路保护相配合。 孤岛islanding 包含负荷和电源…

第一章 语音识别概述

小爱同学&#xff0c;小度小度&#xff0c;天猫精灵&#xff0c;叮咚叮咚……我们身边好像突然就出现了一些可以和我们“聊天”的音箱&#xff0c;图所示为百度智能音箱。 智能音箱与传统音箱最大的区别就是能够听懂我们的语音&#xff0c;人们通过说话就能与电子设备沟通&…

udp和tcp的区别

目录 UDP 和 TCP 的区别 1. 连接性 2. 可靠性 3. 数据传输顺序 4. 流量控制和拥塞控制 5. 效率 6. 应用场景 UDP 和 TCP 的 C/C 代码实现区别 1. TCP 服务器端和客户端 TCP 服务器端&#xff08;Server&#xff09; TCP 客户端&#xff08;Client&#xff09; 2. U…

解析PHP文件路径相关常量

PHP文件路径相关常量包括以下几个常量&#xff1a; __FILE__&#xff1a;表示当前文件的绝对路径&#xff0c;包括文件名。 __DIR__&#xff1a;表示当前文件所在的目录的绝对路径&#xff0c;不包括文件名。 dirname(__FILE__)&#xff1a;等同于__DIR__&#xff0c;表示当前…

结合R语言、ArcGIS Pro、ChatGPT+生态学模型(PLUS模型、InVEST模型)的生态系统服务的多情景模拟预测及其应用

随着全球城市化进程的加速与人类活动的频繁&#xff0c;土地利用及生态系统服务面临巨大的压力&#xff0c;水土流失、植被退化、生物多样性丧失等环境问题日益严重。如何在土地供需矛盾中维持生态安全、优化土地利用模式&#xff0c;成为当前生态学与土地规划领域的研究重点。…

堆(Heap)的原理与C++实现

1. 什么是堆&#xff1f; 堆&#xff08;Heap&#xff09;是一种特殊的树形数据结构&#xff0c;通常用于实现优先队列。堆可以分为两种类型&#xff1a; 最大堆&#xff08;Max Heap&#xff09;&#xff1a;每个节点的值都大于或等于其子节点的值。最小堆&#xff08;Min H…

被裁与人生的意义--春节随想

还有两个月就要被迫离开工作了十多年的公司了&#xff0c;整个中国分支全部干掉。不过我有幸安安稳稳的过了一个春节&#xff0c;很知足! 分六七批走人&#xff0c;我是最后一批离开&#xff0c;一百多号同事都没“活到”蛇年。看着一批批仁人志士被“秋后斩首”&#xff0c;马…