算法 最小生成树

算法选择

稠密图:朴素版普利姆算法【因为代码短】

稀疏图:克鲁斯卡尔算法【因为思路简单】

普利姆(Prim)

朴素 Prim

时间复杂度 O(n^2)

适用情况

稠密图

算法流程

集合:当前已经在连通块中的所有点

  1. 初始化距离,将所有距离初始化为正无穷
  2. n 次迭代,因为要加入 n 个点

for(int i = 0; i < n; i ++)

找到集合外距离最近的点,赋给 t

用 t 更新其它点到集合的距离

把 t 加到集合中st[t] = true;

模板

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m;
int g[N][N];
int dist[N];
bool st[N];
int prim() {memset(dist, 0x3f, sizeof dist);//初始化所有距离int res = 0;//最小生成树中所有边之和for (int i = 0;i < n;i++) {//n次迭代int t = -1;for (int j = 1;j <= n;j++) {//找集合外距离最小的点if (!st[j] && (t == -1 || dist[t] > dist[j]))//t==-1说明现在还没有找到任何一个点t = j;//t存当前距离最小的点}if (i && dist[t] == INF)//如果不是第一个点并且dist[t]是正无穷,说明当前图是不连通的,说明不存在最小生成树return INF;if (i)//先累加,再更新,防止自环的加入res += dist[t];for (int j = 1;j <= n;j++)dist[j] = min(dist[j], g[t][j]);//dist表示该点到集合的距离st[t] = true;}return res;
}

例题——Prim求最小生成树

给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

给定一张边带权的无向图G=(V, E),其中V表示图中点的集合,E表示图中边的集合,n=|V|,m=|E|。

由V中的全部n个顶点和E中n-1条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图G的最小生成树。

输入格式

第一行包含两个整数n和m。

接下来m行,每行包含三个整数u,v,w,表示点u和点v之间存在一条权值为w的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

数据范围

1≤n≤500,

1≤m≤10^5,

图中涉及边的边权的绝对值均不超过10000。

输入样例

4 5

1 2 1

1 3 2

1 4 3

2 3 2

3 4 4

输出样例

6

代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m;
int g[N][N];
int dist[N];
bool st[N];
int prim() {memset(dist, 0x3f, sizeof dist);//初始化所有距离int res = 0;//最小生成树中所有边之和for (int i = 0;i < n;i++) {//n次迭代int t = -1;for (int j = 1;j <= n;j++) {//找集合外距离最小的点if (!st[j] && (t == -1 || dist[t] > dist[j]))//t==-1说明现在还没有找到任何一个点t = j;//t存当前距离最小的点}if (i && dist[t] == INF)//如果不是第一个点并且dist[t]是正无穷,说明当前图是不连通的,说明不存在最小生成树return INF;if (i)//先累加,再更新,防止自环的加入res += dist[t];for (int j = 1;j <= n;j++)dist[j] = min(dist[j], g[t][j]);//dist表示该点到集合的距离st[t] = true;}return res;
}
int main() {scanf("%d%d", &n, &m);memset(g, 0x3f, sizeof g);while (m--) {int a, b, c;scanf("%d%d%d", &a, &b, &c);g[a][b] = g[b][a] = min(g[a][b], c);}int t = prim();if (t == INF)puts("impossible");//所有点不连通时不存在最小生成树elseprintf("%d\n", t);return 0;
}

堆优化 Prim

时间复杂度 O(mlogn)

适用情况

稀疏图

克鲁斯卡尔(Kruskal)

时间复杂度 O(mlogm)

适用情况

稀疏图

算法流程

  1. 将所有边按照权重从小到达排序,可以用快排排序 O(mlogm)
  2. 从小到大依次枚举每条边a,b,权重c O(m)

如果a,b不连通,那么将这条边加入集合中

模板

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 200010;
int n, m;
int p[N];
struct Edge {int a, b, w;bool operator<(const Edge& W)const {return w < W.w;}
}edges[N];
int find(int x) {if (p[x] != x)p[x] = find(p[x]);return p[x];
}
int main() {scanf("%d%d", &n, &m);for (int i = 0;i < m;i++) {int a, b, w;scanf("%d%d%d", &a, &b, &w);edges[i] = { a,b,w };}//克鲁斯卡尔算法sort(edges, edges + m);//将所有边按权重排序for (int i = 1;i <= n;i++)//初始化并查集p[i] = i;int res = 0, cnt = 0;for (int i = 0;i < m;i++) {//从小到大枚举所有边int a = edges[i].a, b = edges[i].b, w = edges[i].w;a = find(a), b = find(b);if (a != b) {//两个祖宗节点不连通p[a] = b;//合并两个集合res += w;//res存最小生成树中所有树边权重之和cnt++;//cnt存当前加了多少条边}}if (cnt < n - 1)//不连通puts("impossible");elseprintf("%d\n", res);return 0;}

例题——Kruskal求最小生成树

题目描述

给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

给定一张边带权的无向图G=(V, E),其中V表示图中点的集合,E表示图中边的集合,n=|V|,m=|E|。

由V中的全部n个顶点和E中n-1条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图G的最小生成树。

输入格式

第一行包含两个整数n和m。

接下来m行,每行包含三个整数u,v,w,表示点u和点v之间存在一条权值为w的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

数据范围

1≤n≤10^5,

1≤m≤2∗10^5,

图中涉及边的边权的绝对值均不超过1000。

输入样例

4 5

1 2 1

1 3 2

1 4 3

2 3 2

3 4 4

输出样例

6

代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 200010;
int n, m;
int p[N];
struct Edge {int a, b, w;bool operator<(const Edge& W)const {return w < W.w;}
}edges[N];
int find(int x) {if (p[x] != x)p[x] = find(p[x]);return p[x];
}
int main() {scanf("%d%d", &n, &m);for (int i = 0;i < m;i++) {int a, b, w;scanf("%d%d%d", &a, &b, &w);edges[i] = { a,b,w };}sort(edges, edges + m);for (int i = 1;i <= n;i++)p[i] = i;int res = 0, cnt = 0;for (int i = 0;i < m;i++) {int a = edges[i].a, b = edges[i].b, w = edges[i].w;a = find(a), b = find(b);if (a != b) {p[a] = b;res += w;//res存最小生成树中所有树边权重之和cnt++;//cnt存当前加了多少条边}}if (cnt < n - 1)puts("impossible");elseprintf("%d\n", res);return 0;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/257012.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

水平自动扩容和缩容HPA;API资源对象NetworkPolicy;Kubernetes用户安全控制;Kubernetes创建普通用户示例

水平自动扩容和缩容HPA&#xff1b;API资源对象NetworkPolicy&#xff1b;Kubernetes用户安全控制&#xff1b;Kubernetes创建普通用户示例 水平自动扩容和缩容HPA&#xff08;本部分操作适合K8s版本>1.23.x) HPA全称是Horizontal Pod Autoscaler&#xff0c;翻译成中文是…

Windows 系统彻底卸载 SQL Server 通用方法

Windows 系统彻底卸载 SQL Server 通用方法 无论什么时候&#xff0c;SQL Server 的安装和卸载都是一件让我们头疼的事情。因为不管是 SQL Server 还是 MySQL 的数据库&#xff0c;当我们在使用数据库时因为未知原因出现问题&#xff0c;想要卸载重装时&#xff0c;如果数据库…

[LeetCode]-283. 移动零-1089. 复写零

目录 283. 移动零 描述 解析 代码 1089. 复写零 描述 解析 代码 283. 移动零 283. 移动零https://leetcode.cn/problems/move-zeroes/ 描述 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &…

【Linux--基础IO】

目录 一、系统文件接口1.1 open1.2 write1.3 read1.4 close 二、文件描述符三、文件描述符的分配规则四、重定向4.1输出重定向的原理4.2dup2函数的系统调用 五、缓冲区5.1代码及现象5.2原理解释5.3C语言FILE 六、文件系统6.1磁盘的介绍6.1磁盘的分区管理 7、软硬连接7.1软连接7…

Windows本地如何添加域名映射?(修改hosts文件)

1. DNS(域名系统) Domain Name System(域名系统)&#xff1a;为了加快定位IP地址的速度, 将域名映射进行层层缓存的系统. 目的&#xff1a;互联网通过IP&#xff08;10.223.146.45&#xff09;定位浏览器建立连接&#xff0c;但是我们不易区别IP&#xff0c;为了方便用户辨识I…

使用cmake构建的工程的编译方法

1、克隆项目工程 2、进入到工程目录 3、执行 mkdir build && cd build 4、执行 cmake .. 5、执行 make 执行以上步骤即可完成对cmake编写的工程进行编译 &#xff0c;后面只需执行你的编译结果即可 $ git clone 你想要克隆的代码路径 $ cd 代码文件夹 $ mkdir bu…

【GAMES101】三维变换

games101的第四节课讲了三维变换和观察变换&#xff0c;我们这里先记录一下三维变换的知识&#xff0c;后面再讲观察变换 齐次坐标下的三维变换 类似于解决之前二维变换平移的问题&#xff0c;三维变换下用齐次坐标通过增加一个维度来表示&#xff0c;第四个维度为1表示这是个…

【计算机网络学习之路】HTTP请求

目录 前言 HTTP请求报文格式 一. 请求行 HTTP请求方法 GET和POST的区别 URL 二. 请求头 常见的Header 常见的额请求体数据类型 三. 请求体 结束语 前言 HTTP是应用层的一个协议。实际我们访问一个网页&#xff0c;都会像该网页的服务器发送HTTP请求&#xff0c;服务…

Verilog学习 | 用initial语句写出固定的波形

initial beginia 0;ib 1;clk 0;#10ia 1; #20ib 0;#20ia 0; endalways #5 clk ~clk; 或者 initial clk 0;initial beginia 0;#10ia 1; #40ia 0; endinitial beginib 1;#30 ib 0; endalways #5 clk ~clk;

Linux Component概述和高通V4l2驱动模型

1 Linux为什么要引入Component框架&#xff1f; 为了让subsystem按照一定顺序初始化设备才提出来的。 subsystem中由很多设备模块&#xff0c;内核加载这些模块的时间不确定。子系统内有些模块是需要依赖其它模块先初始化才能进行自己初始化工作(例如v4l2 subdev和v4l2 video …

CentOS系统中设置反向代理服务器的步骤

在CentOS系统中设置反向代理服务器可以帮助你隐藏原始服务器的细节&#xff0c;并提高服务器的安全性。以下是在CentOS系统中设置反向代理服务器的步骤概述&#xff1a; 安装反向代理软件&#xff1a; 常见的反向代理软件包括Nginx和Apache。你可以选择其中之一来作为你的反向…

postgresql从入门到精通 - 第37讲:postgres物理备份和恢复概述

PostgreSQL从小白到专家&#xff0c;是从入门逐渐能力提升的一个系列教程&#xff0c;内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容&#xff0c;希望对热爱PG、学习PG的同学们有帮助&#xff0c;欢迎持续关注CUUG PG技术大讲堂。 第37讲&#…