【模板】最小生成树(C++)

news2024/9/25 17:17:15

题目描述

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

输入格式

第一行包含两个整数 N , M N,M N,M,表示该图共有 N N N 个结点和 M M M 条无向边。

接下来 M M M 行每行包含三个整数 X i , Y i , Z i X_i,Y_i,Z_i Xi,Yi,Zi,表示有一条长度为 Z i Z_i Zi 的无向边连接结点 X i , Y i X_i,Y_i Xi,Yi

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

样例 #1

样例输入 #1

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

样例输出 #1

7

提示

数据规模:

对于 20 % 20\% 20% 的数据, N ≤ 5 N\le 5 N5 M ≤ 20 M\le 20 M20

对于 40 % 40\% 40% 的数据, N ≤ 50 N\le 50 N50 M ≤ 2500 M\le 2500 M2500

对于 70 % 70\% 70% 的数据, N ≤ 500 N\le 500 N500 M ≤ 1 0 4 M\le 10^4 M104

对于 100 % 100\% 100% 的数据: 1 ≤ N ≤ 5000 1\le N\le 5000 1N5000 1 ≤ M ≤ 2 × 1 0 5 1\le M\le 2\times 10^5 1M2×105 1 ≤ Z i ≤ 1 0 4 1\le Z_i \le 10^4 1Zi104

样例解释:

所以最小生成树的总边权为 2 + 2 + 3 = 7 2+2+3=7 2+2+3=7

解题思路:

本题是最小生成树的模板题,这里介绍如何将一张图变成一棵最小生成树

最小生成树包含图中的所有节点,符合树的特性(无环、重边),同时要求这棵树的边权和最小

图可以变成一棵树的前提是图是连通的

接下来介绍prim算法

prim算法的本质是贪心

基本思想:首先任意选一个节点加入树中,

然后尝试由新加入的节点更新其他节点到树的最短距离

更新之后,加入距离树最近的节点,如此循环

思想很好理解吧,接下来介绍如何实现

首先要区分加入树和没有加入树的节点,这很容易实现,通过一个标记数组book即可

如何获取到树的最近节点是关键

获取方法一:

要知道到树的最近节点,就要知道每一个节点到树的最短距离

所以开一个数组dist维护最短距离

每加入一个新节点node,尝试用该新节点去更新最短距离数组dist

然后从更新后的数组选出距离树最近的节点temp加入,如此循环即可

bool prim() {
	int node = 1;
	dist[node] = 0;
	book[node] = true;//初始化
	
	for (int i = 2; i <= n; i++) {//循环加入n - 1个节点
		int temp = 0;
		int min_dist = NaN;//初始化
		
		for (int j = 1; j <= n; j++) {//尝试更新到树的最短距离
			if (!book[j]) {//未加入树
            	if (dist[j] > map[node][j]) {
					dist[j] = map[node][j];
				}
				if (min_dist > dist[j]) {
					min_dist = dist[j];
					temp = j;
				}
			}
		}
		
		if (temp) {//找到新节点
			book[temp] = true;
			node = temp;
		}
		else false;//图不连通,无法生成最小生成树
	}
	
	return true;//生成最小生成树
}

获取方法二:

采用优先队列 + 链式前向星实现,不了解的建议先去学习一下

思路基本一致,不再说明

这里特别说明几点:1)pair<int, int>(最短距离, 节点);2)保证队首节点距离树最近

void prim() {
	//初始化
	dist[1] = 0;
	p_q.push(pair<int, int>(0, 1));

	while (!p_q.empty()) {
		int node = p_q.top().second;
		p_q.pop();//取出首节点

		if (book[node]) continue;//已加入树
		book[node] = true;//未加入树

		for (int i = head[node]; i != -1; i = edges[i].next) {//尝试更新到树的最小距离
			int v = edges[i].v;
			if (!book[v] && dist[v] > edges[i].p) {//更新
				dist[v] = edges[i].p;
				p_q.push(pair<int, int>(dist[v], v));
			}
		}
	}
}

这里采用方法二解决本题

学会了如何生成最小生成树,本题就会迎刃而解

需要做的只是累计加入树的节点数量,判断是否生成成功

累计数的边权和,如果生成成功,输出

AC代码如下

//最小生成树
#include <iostream>
#include <vector>
#include <queue>
#include <memory.h>
using namespace std;
const int max_n = 5000;
const int max_m = 2e5;
const int max_z = 1e4;
const int NaN = 0x3F3F3F3F;

class greater_queue {
public:
	bool operator()(pair<int, int>p_1, pair<int, int>p_2) {
		return p_1.first > p_2.first;
	}
};

priority_queue<pair<int, int>, vector<pair<int, int>>, greater_queue>p_q;
struct edge { int v, p, next; }edges[max_m * 2];
int head[max_n + 1] = { -1 };
int tot = -1;
int dist[max_n + 1] = { NaN };
int book[max_n + 1] = { false };//最小生成树
int sum_dist = 0, sum_node = 0;

void add_edge(int u, int v, int p) {
	edges[++tot] = { v,p,head[u] }; head[u] = tot;
	edges[++tot] = { u,p,head[v] }; head[v] = tot;
}

void prim() {
	//初始化
	dist[1] = 0;
	p_q.push(pair<int, int>(0, 1));

	while (!p_q.empty()) {
		int node = p_q.top().second;
		p_q.pop();//取出首节点

		if (book[node]) continue;//已加入树
		book[node] = true;//未加入树
		sum_dist += dist[node];//累加边权
		sum_node--;//未加入的节点数量 - 1

		for (int i = head[node]; i != -1; i = edges[i].next) {//尝试更新到树的最小距离
			int v = edges[i].v;
			if (!book[v] && dist[v] > edges[i].p) {//更新
				dist[v] = edges[i].p;
				p_q.push(pair<int, int>(dist[v], v));
			}
		}
	}
}

int main() {
	memset(head + 1, -1, sizeof(int) * max_n);
	memset(dist + 1, 0x3F, sizeof(int) * max_n);
	int n, m, u, v, p;
	cin >> n >> m;
	sum_node = n;
	for (int i = 0; i < m; i++) {
		cin >> u >> v >> p;
		add_edge(u, v, p);
	}

	prim();

	if (sum_node) cout << "orz";
	else cout << sum_dist;
	return 0;
}

当然,生成最小生成树还有其他的方法,如并查集等,这里放一个我写的并查集传送门qwq

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计师必备的免费样机素材

很多设计师会用样机模型来展示自己的作品&#xff0c;让设计图案、应用界面等作品应用到实物效果图中&#xff0c;能体现作品的最终效果&#xff0c;更加形象逼真。哪里能下载到样机模板呢&#xff1f;今天我就推荐6个网站帮你解决&#xff0c;赶紧收藏&#xff01; 1、菜鸟图库…

20230109测试ToyBrick的RK3588开发板运行Buildroot的V0.02版本(20220312)

20230109测试ToyBrick的RK3588开发板运行Buildroot的V0.02版本&#xff08;20220312&#xff09; 2023/1/9 18:03 https://wiki.t-firefly.com/zh_CN/Firefly-Linux-Guide/manual_buildroot.html 1. Buildroot 使用手册 1.1. 桌面应用 官方发布的 Buildroot 固件&#xff0c;默…

RabbitMQ学习一【尚硅谷】

一、消息队列 1、MQ的相关概念 2、RabbitMQ 2.1 四大核心概念 生产者&#xff1a; 交换机&#xff1a;交换机是 RabbitMQ非常重要的一个部件&#xff0c;一方面它接收来自生产者的消息&#xff0c;另一方面它将消息 推送到队列中。交换机必须确切知道如何处理它接收到的消息…

一文详解Linux Python3安装

在公司申请了一台CentOS 7的Linux版本虚拟机&#xff0c;需要安装一个Python3的环境&#xff0c;定期进行特定任务处理。这里对CentOS 7配置Python3环境的步骤进行了记录&#xff0c;供大家参考。 本文基于如下Linux系统版本&#xff1a; 一、默认Python版本 默认情况下&am…

Excelize 2.7.0 发布, 2023 年首个更新

Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库&#xff0c;基于 ECMA-376&#xff0c;ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式&#xf…

C 程序设计教程(13)—— 顺序结构程序设计练习题

C 程序设计教程&#xff08;13&#xff09;—— 顺序结构程序设计练习题 该专栏主要介绍 C 语言的基本语法&#xff0c;作为《程序设计语言》课程的课件与参考资料&#xff0c;用于《程序设计语言》课程的教学&#xff0c;供入门级用户阅读。 目录C 程序设计教程&#xff08;1…

【openGauss】在openEuler(ARM架构)上安装openGauss(一主两备含CM版)

一、系统版本介绍 当前案例中的openGauss安装&#xff0c;底层操作系统为openEuler-20.03-LTS版本&#xff0c;当前openGauss对Python版本兼容性最好的是Python 3.6版本与Python 3.7版本&#xff0c;该实验使用的openEuler版本自带Python 3.7.4&#xff0c;不需要再自行安装 二…

汽车电子系统网络安全活动

声明 本文是学习GB-T 38628-2020 信息安全技术 汽车电子系统网络安全指南. 下载地址 http://github5.com/view/764而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 汽车电子系统网络安全活动 7.1 概念设计阶段 7.1.1 概述 概念设计阶段的活动流程如图…

房产管理系统分布架构分析

一、数图互通房产管理系统采用分布式架构下的高可用设计&#xff1a; &#xff08;1)可以避免因单点故障造成系统平台宕机&#xff1a; a、负载均衡技术&#xff08;failover &#xff0c;选址&#xff0c;硬件负载&#xff0c;软件负载&#xff0c;去中心化负载&#xff08;g…

tp5处理前端上传的图片文件

前端上传了一个图片文件,tp5框架如何处理 效果图&#xff1a; 效果图一: 效果图二: 如果需要看前端如何展示、删除上传的缩略图请到此篇博客&#xff1a; 前端&#xff1a; <form id"upload_pic_wrap" target"upload_file" enctype"multipar…

任务间通讯

信号量与邮箱 系统中的多个任务在运行时&#xff0c;经常需要互相无冲突地访问同一个共享资源&#xff0c;或者需要互相支持和依赖&#xff0c;甚至有时还要互相加以必要的限制和制约&#xff0c;才保证任务的顺利运行。因此&#xff0c;操作系统必须具有对任务的运行进行协调…

C++11引入的尾置返回类型

C11引入的尾置返回类型一、什么是尾置返回类型(trailing return type)二、尾置返回的典型场景2.1 常规方式如何返回数组指针2.2 使用尾置返回类型三、尾置返回类型的应用四、总结一、什么是尾置返回类型(trailing return type) 我们先来看一下传统的函数是怎么定义的&#xff…

Leetcode N皇后

题目链接 Leetcode.51 N 皇后 Leetcode.52 N皇后 II N皇后 题目描述 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个…

如何在Vue组件中调用封装好的外部js文件方法

文章目录1、前言2、抽离基本业务js3、在具体组件中调用3.1 引入3.2 组件中调用3.3 实现的效果4、实际项目中的运用4.1 核心展示将一些常用的方法&#xff0c;比如字符串格式化呀&#xff0c;时间格式话呀&#xff0c;常用的表单验证方法呀等等。可以抽离出为基础的业务。在组件…

【Linux】echo命令用法详解

作者&#xff1a;柒号华仔 个人主页&#xff1a;欢迎访问我的主页 个人信条&#xff1a;星光不问赶路人,岁月不负有心人。 个人方向&#xff1a;专注于5G领域&#xff0c;同时兼顾其他网络协议&#xff0c;编解码协议&#xff0c;C/C&#xff0c;linux等&#xff0c;感兴趣的小…

【MySQL】帮助的使用,清晰地解析——?/help命令

MySQL帮助的使用为什么需要‘帮助’命令实际使用? contents 命令显示可供查询的分类子类别内容展示查阅帮助&#xff08;show命令的使用&#xff09;show 命令的用法展示各个表状态信息展示一个表的字段信息为什么需要‘帮助’命令 某个操作的语法忘记了&#xff0c;快速查找…

禅道研发项目管理系统命令注入漏洞(MPS-2023-0418)

漏洞描述 禅道是一款国产开源项目管理软件。 禅道研发项目管理系统存在系统命令注入漏洞&#xff0c;具有后台登陆权限的攻击者可以利用此漏洞执行任意命令&#xff0c;进而控制服务器。 漏洞名称禅道研发项目管理系统命令注入漏洞漏洞类型命令注入发现时间2023/1/6漏洞影响…

分享48个Go源码,总有一款适合您

Go源码 分享48个Go源码&#xff0c;总有一款适合您 Go源码下载链接&#xff1a;https://pan.baidu.com/s/1FhQ6NzB3TWsv9res1OsJaA?pwdr2d3 提取码&#xff1a;r2d3 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;…

【安全】RefererXMLHttpRequest部分内容

目录 Referer Referrer-policy 设置referer 盗链 防盗链的工作原理 防盗链的三种方式 如何绕过图片防盗链 XMLHttpRequest 构造函数 XMLHttpRequest 的实例属性 XMLHttpRequest.readyState XMLHttpRequest.onreadystatechange XMLHttpRequest.response XMLHttpRe…

如何从区块链上数据识别出套利行为或者抢跑三明治交易

如何识别链上套利行为或者抢跑夹子三明治行为或交易 识别原子 MEV交易 鉴于交易可以任意复杂并且可以有无数未知交易模式&#xff0c;使用特定交易模式匹配的方法无法应对新的 MEV 模式。为了确定交易中是否发生套利&#xff0c;我们需要对交易进行通用抽象。 以下是我们为认…