prim算法精讲

53. 寻宝(第七期模拟笔试)

题目描述:

在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。

不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将所有岛屿联通起来。

给定一张地图,其中包括了所有的岛屿,以及它们之间的距离。以最小化公路建设长度,确保可以链接到所有岛屿。

输入描述:

第一行包含两个整数V和E,V代表顶点数,E代表边数。顶点编号是从1到V。例如:V=2,一个有两个顶点,分别是1和2。

接下来共有E行,每行三个整数v1,v2和val,v1和v2为边的起点和终点,val代表边的权值。

输出描述:

输出联通所有岛屿的最小路径总距离

输入示例:

7 11
1 2 1
1 3 1
1 5 2
2 6 1
2 4 2
2 3 2
3 4 1
4 5 1
5 6 2
5 7 1
6 7 1

输出示例:

6

解题思路

本题是最小生成树的模板题,最小生成树可以使用prim算法也可以使用kruskal算法计算出来。

最小生成树是所有节点的最小连通子图,即:以最小的成本(边的权值)将图中所有节点链接到一起。

图中有n个节点,那么一定可以用n-1条边将所有节点连接到一起。

那么如何选择这n-1条边就是最小生成树算法的任务所在。

prim算法,是从节点的角度采用贪心的策略每次寻找距离最小生成树最近的节点并加入到最小生成树中。

prim三部曲

  1. 第一步,选距离生成树最近节点
  2. 第二步,最近节点加入生成树
  3. 第三步,更新非生成树节点到生成树的距离(即更新minDist数组)

“每次寻找距离最小生成树最近的节点并加入到最小生成树中”,就用到了minDist数组,minDist数组用来记录每一个节点距离最小生成树的最近距离

初始状态

minDist数组里的数值初始化为最大数,现在还没有最小生成树,默认每个节点距离最小生成树是最大的,这样后面我们在比较的时候,发现更近的距离,才能更新到minDist数组上。

第一步:选距离生成树最近节点

选择距离最小生成树最近的节点,加入到最小生成树,刚开始还没有最小生成树,所以随便选一个节点加入就好

第二步:最近节点加入生成树

此时节点1已经算最小生成树的节点。

第三步:更新非生成树节点到生成树的距离(即更新minDist数组)
#include<iostream>
#include<vector>
#include<climits>using namespace std;
int main(){int v,e;cin>>v>>e;int x,y,k;vector<vector<int>> grid(v+1,vector<int>(v+1,10001));while(e--){cin>>x>>y>>k;grid[x][y]=k;grid[y][x]=k;}// 所有节点到最小生成树的最小距离vector<int> minDist(v+1,10001);// 这个节点是否在树里vector<bool> isInTree(v+1,false);
// 我们只需要循环 n-1次,建立 n - 1条边,就可以把n个节点的图连在一起for(int i=1;i<v;i++){//1、第一步:选距离生成树最近节点int cur=-1;// 选中哪个节点 加入最小生成树int minVal=INT_MAX;for(int j=1;j<=v;j++){// 1 - v,顶点编号,这里下标从1开始//  选取最小生成树节点的条件://  (1)不在最小生成树里//  (2)距离最小生成树最近的节点if(!isInTree[j]&&minDist[j]<minVal){minVal=minDist[j];cur=j;}}//2、第二步:最近节点(cur)加入生成树isInTree[cur]=true;//3、第三步:更新非生成树节点到生成树的距离(即更新minDist数组)// cur节点加入之后, 最小生成树加入了新的节点,那么所有节点到 最小生成树的距离(即minDist数组)需要更新一下// 由于cur节点是新加入到最小生成树,那么只需要关心与 cur 相连的 非生成树节点 的距离 是否比 原来 非生成树节点到生成树节点的距离更小了呢for(int j=1;j<=v;j++){// 更新的条件:// (1)节点是 非生成树里的节点// (2)与cur相连的某节点的权值 比 该某节点距离最小生成树的距离小// 很多录友看到自己 就想不明白什么意思,其实就是 cur 是新加入 最小生成树的节点,那么 所有非生成树的节点距离生成树节点的最近距离 由于 cur的新加入,需要更新一下数据了if(!isInTree[j]&&grid[cur][j]<minDist[j]){minDist[j]=grid[cur][j];}}}int res=0;for(int i=2;i<=v;i++){res+=minDist[i];}cout<<res<<endl;
}

拓展

上面讲解的是记录了最小生成树所有边的权值,如果让打印出来最小生成树的每条边呢?或者说要把这个最小生成树画出来呢?

此时有两个问题:

  • 1、用什么结构来记录
  • 2、如何记录

如果记录边,其实就是记录两个节点就可以,两个节点连成一条边。

如何记录两个节点呢?

我们使用一维数组就可以记录。parent[节点编号] = 节点编号,这样就把一条边记录下来了。(当然如果节点编号非常大,可以考虑使用map)

minDist数组里记录的其实也是最小生成树的边的权值。”

既然minDist数组记录了最小生成树的边,是不是就是在更新minDist数组的时候,去更新parent数组来记录一下对应的边呢。

所以在prim三部曲中的第三步,更新parent数组,代码如下:

for (int j = 1; j <= v; j++) {if (!isInTree[j] && grid[cur][j] < minDist[j]) {minDist[j] = grid[cur][j];parent[j] = cur; // 记录最小生成树的边 (注意数组指向的顺序很重要)}
}

如果 parent[cur] = j 这么写,最后更新的逻辑是 parent[1] = 2, parent[1] = 3, parent[1] = 4,最后只能记录节点1与节点4相连,其他相连情况都被覆盖了。

如果这么写 parent[j] = cur,那就是 parent[2] = 1, parent[3] = 1, parent[4] = 1 ,这样才能完整表示出节点1与其他节点都是链接的,才没有被覆盖。

kruskal算法精讲

53. 寻宝(第七期模拟笔试)

解题思路

prim 算法是维护节点的集合,而 Kruskal 是维护边的集合

kruscal的思路:

  • 边的权值排序,因为要优先选最小的边加入到生成树里
  • 遍历排序后的边
    • 如果边首尾的两个节点在同一个集合,说明如果连上这条边图中会出现环
    • 如果边首尾的两个节点不在同一个集合,加入到最小生成树,并把两个节点加入同一个集合

而判断两个节点是否在同一个集合中,就用到了前面讲的并查集;

#include<iostream>
#include<vector>
#include<algorithm>using namespace std;struct Edge{int l,r,val;
};
int n=10001;
vector<int> father(n,-1);void init(){for(int i=0;i<n;i++){father[i]=i;}
}
int find(int u){if(father[u]==u)return u;father[u]=find(father[u]);return father[u];
}
void join(int u,int v){u=find(u);v=find(v);if(u==v)return;father[v]=u;
}int main(){int v,e;cin>>v>>e;int x,y,k;vector<Edge> edges; int res=0;vector<vector<int>> grid(v+1,vector<int>(v+1,10001));while(e--){cin>>x>>y>>k;edges.push_back({x,y,k});}sort(edges.begin(),edges.end(),[](const Edge& a,const Edge& b){return a.val<b.val;});init();for(Edge edge:edges){int i=find(edge.l);int j=find(edge.r);if(i!=j){res+=edge.val;join(i,j);}}cout<<res<<endl;return 0;
}

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

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

相关文章

最短路问题从入门到负权最短路

一&#xff0c;BFS层次最短路/*题目描述 题目描述 给出一个 N 个顶点 M 条边的无向无权图&#xff0c;顶点编号为 1∼N。 问从顶点 1 开始&#xff0c;到其他每个点的最短路有几条。 输入格式 第一行包含 2 个正整数 N,M&#xff0c;为图的顶点数与边数。 接下来 M 行&#xff…

AI智能体小白入门指南

AI智能体小白入门指南 ——什么是AI智能体&#xff1f;它们如何工作&#xff1f; 一、AI智能体是什么&#xff1f; AI智能体&#xff08;AI Agent&#xff09;是能感知环境、自主决策并执行动作的人工智能系统。 类比理解&#xff1a;像一个“虚拟机器人”或“数字助手”&#…

《设计模式》策略模式

1.策略模式定义 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一组算法&#xff0c;将每个算法封装起来&#xff0c;并使它们可以相互替换&#xff0c;从而让算法的变化独立于使用它的客户&#xff08;Client&#xff09;。 换…

AWS DMS 深度解析:从迁移任务到复制任务 - 全流程指南与最佳实践

AWS Database Migration Service (DMS) 是一项强大的云服务,用于在源数据库和目标数据库之间安全地迁移数据。其核心优势在于支持几乎零停机时间的迁移,这主要归功于其“变更数据捕获 (CDC)”功能。理解迁移任务 (Migration Task) 和复制任务 (Replication Task) 的关系与操作…

国企社招 | 中国邮政2025年社会招聘开启

添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 原文链接&#xff1a;“邮”你“政”好 | 广东邮政2025年社会…

linux添加自启动

linux添加自启动 配置步骤&#xff1a; 创建systemd服务文件 sudo nano /etc/systemd/system/tme-vod.service将下面artifact中的内容复制到该文件中。 [Unit] DescriptionTME VOD Service Afternetwork.target[Service] Typesimple Userroot Grouproot WorkingDirectory/data/…

轻量级解决方案:如何高效处理Word转PDF?

文档格式转换时&#xff0c;手动逐个处理总显得效率低下。它的体积小巧&#xff0c;不到1MB&#xff0c;且无界面设计&#xff0c;运行极简&#xff1a;将其与Word文件放入同一目录&#xff0c;双击启动&#xff0c;程序便会自动完成所有文档的PDF转换。操作零复杂度&#xff0…

Redis 数据倾斜

Redis 数据倾斜指的是在 Redis 集群模式下&#xff0c;数据&#xff08;以及相应的访问请求和负载&#xff09;在各个分片&#xff08;Shard&#xff09;之间分布严重不均匀的现象。这会导致部分节点成为热点或超载&#xff0c;而其他节点资源闲置&#xff0c;最终引发性能瓶颈…

Java基础-TCP通信(多发多收和一发一收)

目录 案例要求&#xff1a; 实现思路&#xff1a; 代码&#xff1a; User:客户端 Client:服务端 总结&#xff1a; 案例要求&#xff1a; 实现TCP通信的多发多收和一发一收,多发多收去掉各自的while循环就是一发一收,本文只模拟一发一收 实现思路&#xff1a; 客户端(U…

WinForm 对话框的 Show 与 ShowDialog:阻塞与非阻塞的抉择

目录 核心概念&#xff1a;阻塞与非阻塞 Show 与 ShowDialog 的详细对比 代码示例&#xff1a;两种方式的实现差异 使用 Show () 显示非模态对话框 使用 ShowDialog () 显示模态对话框 适用场景分析 适合使用 Show () 的场景 适合使用 ShowDialog () 的场景 最佳实践与…

晓知识: 动态代理与静态代理的区别

动态代理与静态代理的区别 代理模式是一种常见的设计模式&#xff0c;用于在不修改原始类的情况下扩展其功能。代理分为静态代理和动态代理两种&#xff0c;它们在实现方式、适用场景和灵活性上有显著差异。 静态代理 静态代理在编译时就已经确定代理类和被代理类的关系。代理类…

Linux系统编程Day9 -- gdb (linux)和lldb(macOS)调试工具

往期内容回顾 Git 教程&#xff08;初阶&#xff09; 基于Linux系统知识的第一个程序 自动化构建工具-make/Makefile gcc/g编译及链接 Vim工具的使用 Linux常用工具&#xff08;yum与vim&#xff09; 一、 Linux 下的调试工具 GDB 一、为什么要学习 GDB&#xff1f; 调试是开发…

数据结构(17)排序(下)

一、计数排序计数排序又称为鸽巢原理&#xff0c;是对哈希直接定址法的变形应用。操作步骤如下&#xff1a;①统计相同元素出现的次数 ②根据统计的结果将序列回收到原来的序列中比如&#xff0c;现在有一个数组{6,1,2,9,4,2,4,1,4}。该数组中&#xff0c;元素1出现两次&#…

深度解析 Spring Boot 循环依赖:原理、源码与解决方案

在 Spring Boot 开发中,循环依赖是一个常见且容易被忽视的技术点。当两个或多个 Bean 相互引用时,就会形成循环依赖(如 A 依赖 B,B 依赖 A)。初学者往往会困惑:Spring 为什么能自动处理这种看似矛盾的依赖关系?本文将从原理、源码实现到解决方案,全方位剖析 Spring Boo…

数据库的基本操作(约束与DQL查询)

一、约束约束是在表上强制执行的数据规则&#xff0c;用于确保数据的完整性和一致性&#xff08;1&#xff09;约束类型MySQL中支持多种约束类型&#xff1a;①主键约束&#xff08;PRIMARY KEY&#xff09; ②自增约束&#xff08;AUTO_INCREMENT&#xff09;③非空约束…

HP Pavilion G6 笔记本安装Ubuntu开机后自动进入飞行模式的问题解决

问题一台HP Pavilion G6 笔记本 &#xff0c;安装了Ubuntu24.04版本&#xff0c;开机后&#xff0c;直接进入飞行模式&#xff0c;导致无法使用Wifi,且使用fnf10的组合键&#xff0c;也无法关闭飞行模式。使用fnf10键&#xff0c;可以看到提示显示飞行模式&#xff0c;但无法关…

LLM:MoE原理与实现探索

文章目录前言一、Deepseek Moe二. Moe架构1. Expert2. Gate3. MoE Module三、Auxiliary Loss总结前言 MoE&#xff08;Mixture of Experts) 已经逐渐在LLM中广泛应用&#xff0c;其工程部署相关目前也有了越来越多的支持&#xff0c;本文主要记录一下MoE的基本模块构造与原理。…

基于领域事件驱动的微服务架构设计与实践

引言&#xff1a;为什么你的微服务总是"牵一发而动全身"&#xff1f; 在复杂的业务系统中&#xff0c;你是否遇到过这样的困境&#xff1a;修改一个订单服务&#xff0c;却导致支付服务异常&#xff1b;调整库存逻辑&#xff0c;用户服务开始报错。这种"蝴蝶效应…

如何使用curl编程来下载文件

libcurl 是一个功能强大的跨平台网络传输库&#xff0c;支持多种协议。 本篇来介绍libcul的C语言编程&#xff0c;实现一个文件下载的功能。 1 curl基础介绍 1.1 核心数据结构 1.1.1 CURL句柄 CURL是libcurl 的核心句柄&#xff0c;每个请求对应一个 CURL 实例&#xff0c;…

大语言模型提示工程与应用:ChatGPT提示工程技术指南

ChatGPT提示工程 学习目标 在本课程中&#xff0c;我们将学习更多关于ChatGPT的最新提示工程技术。 相关知识点 ChatGPT提示工程 学习内容 1 ChatGPT提示工程 ChatGPT是OpenAI研发的新型对话模型&#xff0c;具备多轮对话能力。该模型通过人类反馈强化学习(RLHF)训练&am…