当前位置: 首页 > news >正文

代码随想录训练营 Day57打卡 图论part07 53. 寻宝(prim,kruskal算法)

代码随想录训练营 Day57打卡 图论part07

卡码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
提示信息
数据范围:
2 <= V <= 10000;
1 <= E <= 100000;
0 <= val <= 10000;
如下图,可见将所有的顶点都访问一遍,总距离最低是6.

版本一 prim算法

这是一个典型的 Prim算法 问题,目的是找到图的最小生成树(MST),即连接所有节点的总边权值最小的树。

def prim(v, e, edges):# 初始化一个 v+1 * v+1 的邻接矩阵,初始值为一个很大的数grid = [[float('inf')] * (v + 1) for _ in range(v + 1)]# 读取所有边的信息,构建邻接矩阵for x, y, k in edges:grid[x][y] = kgrid[y][x] = k# 最小生成树中每个节点与其他树节点的最小距离minDist = [float('inf')] * (v + 1)# 标记节点是否在最小生成树中isInTree = [False] * (v + 1)# 从第一个节点开始,设定它的初始距离为0minDist[1] = 0# 最小生成树的权值总和result = 0# Prim算法,执行 v-1 次,选择 v-1 条边构造最小生成树for _ in range(1, v):  # v-1次cur = -1  # 当前选中要加入树的节点minVal = float('inf')# 第一步:选择离生成树最近的节点for j in range(1, v + 1):if not isInTree[j] and minDist[j] < minVal:minVal = minDist[j]cur = j# 第二步:将选中的节点加入最小生成树isInTree[cur] = Trueresult += minVal# 第三步:更新所有非生成树节点到生成树的最小距离for j in range(1, v + 1):if not isInTree[j] and grid[cur][j] < minDist[j]:minDist[j] = grid[cur][j]return result# 读取输入
v, e = map(int, input().split())  # v 为节点数,e 为边数
edges = []
for _ in range(e):x, y, k = map(int, input().split())edges.append((x, y, k))# 调用 Prim 算法并输出结果
print(prim(v, e, edges))
  1. 邻接矩阵:我们用 grid 来表示邻接矩阵,初始值为 float(‘inf’),表示两个节点之间没有边连接。对于每个输入的边 (x,
    y, k),我们设置 grid[x][y] = k 和 grid[y][x] = k,因为这是一个无向图。
  2. minDist 数组:该数组用于存储每个节点到已加入最小生成树的最近距离,初始值为 float(‘inf’),表示未与最小生成树相连。
  3. isInTree 数组:该数组用于记录每个节点是否已经被加入最小生成树。
  4. Prim算法:我们进行 v-1次迭代,每次选择一个离当前生成树最近的节点,加入最小生成树,并更新所有未加入树的节点与当前生成树的最小距离。
  5. 结果计算:在每次迭代时,将选中的边的权值加到最终结果 result 中,最后返回最小生成树的权值总和。

时间复杂度:

  • 构建邻接矩阵:时间复杂度是 O(v^2),因为我们存储了所有节点对之间的边。
  • 主循环:由于每次我们都需要遍历 v 个节点,寻找最近的节点,因此每次循环的复杂度为 O(v),总的时间复杂度为 O(v^2)。

版本二 kruskal算法

Kruskal算法是一种贪心算法,它的目标是通过选择最小的边来构建最小生成树。Kruskal算法的核心思想是维护边的集合,而不是像Prim算法那样维护节点的集合

Kruskal算法的步骤:

  1. 边权排序:首先对所有的边按权值从小到大排序,因为我们要优先选择权值最小的边。
  2. 并查集判断:遍历每条边,判断它连接的两个节点是否已经属于同一个集合(即是否已经连通)。如果两个节点属于同一个集合,添加这条边将形成环路,应该跳过这条边;如果两个节点不属于同一个集合,就可以添加这条边,并将两个节点合并到同一个集合。
  3. 结束条件:当我们选择了 n-1 条边时(其中 n 是图中的节点数),生成树构建完毕。

Kruskal算法的关键数据结构是并查集(Union-Find),并查集可以帮助我们高效地判断两个节点是否已经连通。

Kruskal算法的关键点:

  • 并查集:用于维护节点的集合关系,主要支持两个操作:

    Find:查找某个节点所在集合的根节点,使用路径压缩加速查找。
    Union:将两个节点所在的集合合并。

  • 边权排序:对所有的边按权值从小到大排序,以贪心策略构建最小生成树。

class Edge:def __init__(self, l, r, val):self.l = l  # 边的左端点self.r = r  # 边的右端点self.val = val  # 边的权值# 节点的最大数量假设为 10001
n = 10001
father = list(range(n))  # 并查集的父节点数组,初始时每个节点的父节点都是它自己# 初始化并查集
def init():global fatherfather = list(range(n))# 并查集的查找操作,使用路径压缩优化
def find(u):if u != father[u]:father[u] = find(father[u])  # 路径压缩,将节点 u 直接指向根节点return father[u]# 并查集的合并操作,将节点 u 和节点 v 所在的集合合并
def join(u, v):u = find(u)v = find(v)if u != v:father[v] = u  # 将 v 的根节点指向 u 的根节点# Kruskal算法,求最小生成树的权值总和
def kruskal(v, edges):edges.sort(key=lambda edge: edge.val)  # 将边按权值从小到大排序init()  # 初始化并查集result_val = 0  # 最小生成树的权值总和edge_count = 0  # 记录已经加入生成树的边数# 遍历排序后的边for edge in edges:if edge_count == v - 1:  # 如果已经选择了 v-1 条边,生成树构建完毕break# 查找边的两个端点的根节点x = find(edge.l)y = find(edge.r)# 如果两个端点不属于同一个集合,说明可以加入最小生成树if x != y:result_val += edge.val  # 累加边的权值join(x, y)  # 合并这两个端点的集合edge_count += 1  # 增加已加入的边数return result_val  # 返回最小生成树的权值总和# 主函数,处理输入并输出结果
if __name__ == "__main__":import sysinput = sys.stdin.read  # 读取标准输入data = input().split()v = int(data[0])  # 节点数量e = int(data[1])  # 边的数量edges = []  # 存储所有边index = 2for _ in range(e):v1 = int(data[index])  # 边的左端点v2 = int(data[index + 1])  # 边的右端点val = int(data[index + 2])  # 边的权值edges.append(Edge(v1, v2, val))  # 将边加入到列表中index += 3# 调用 Kruskal 算法求解最小生成树的权值总和result_val = kruskal(v, edges)# 输出最小生成树的总权值print(result_val)

卡码题目链接
题目文章讲解

总结

Prim算法和Kruskal算法都是用于求解 最小生成树(MST) 的经典贪心算法。尽管它们的目标相同,但它们的实现方式和使用的数据结构有所不同。

  1. 思路与操作对象的区别
    Prim算法:
    节点为中心:Prim算法从一个起始节点开始,不断向已连接的生成树中添加最小边。它通过逐步扩展树的节点来构建最小生成树。
    局部贪心策略:每次选择的都是与已构建的生成树相连的最小边。
    Kruskal算法:
    边为中心:Kruskal算法从所有边中选择权值最小的边开始,逐步将未连通的部分通过边连接起来。
    全局贪心策略:Kruskal算法直接对所有边进行排序,然后逐步选择不会形成环的最小边。

  2. 使用的数据结构
    Prim算法:
    邻接矩阵或邻接表:通常使用邻接矩阵或邻接表来表示图,逐步更新已连接节点与其他未连接节点之间的最小权值。
    优先队列(可选):使用优先队列(堆)优化查找最小边的操作,复杂度可以优化为 O(E log V)。
    Kruskal算法:
    边列表:Kruskal算法将所有边按权值排序,然后依次选择边,因此直接使用边的列表。
    并查集(Union-Find):Kruskal算法需要并查集来判断两个节点是否已经在同一集合中,用于检测是否形成环路。

  3. 适用的图类型
    Prim算法:
    适用于稠密图:由于 Prim算法逐步扩展已连接的节点集合,因此在边数较多的稠密图中表现较好。
    时间复杂度为 O(V^2)(邻接矩阵)或 O(E log V)(使用优先队列的邻接表)。
    Kruskal算法:
    适用于稀疏图:Kruskal算法对边进行排序并依次选择最小边,在边数较少的稀疏图中表现较好。
    时间复杂度为 O(E log E),其中 E 是边数。

  4. 执行流程
    Prim算法:
    从任意起始节点开始,将该节点标记为已访问。
    每次选择已访问节点集合中与未访问节点集合之间的最小边,将新节点加入最小生成树。
    重复该过程,直到所有节点都被访问。
    Kruskal算法:
    将所有边按权值从小到大排序。
    依次选择最小的边,如果该边连接的两个节点不在同一集合中,则将它们加入最小生成树,并使用并查集进行合并。
    重复该过程,直到树中包含 n-1 条边。

  5. 结束条件
    Prim算法:
    当所有节点都已加入生成树时,算法结束。
    Kruskal算法:
    当选中的边数达到 n-1 条时,算法结束(其中 n 是节点数)。

相关文章:

代码随想录训练营 Day57打卡 图论part07 53. 寻宝(prim,kruskal算法)

代码随想录训练营 Day57打卡 图论part07 卡码53. 寻宝 题目描述 在世界的某个区域&#xff0c;有一些分散的神秘岛屿&#xff0c;每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路&#xff0c;方便运输。 不同岛屿之间&#xff0c;路途距离不同&#xff0c;…...

Hibernate QueryPlanCache 查询计划缓存引发的内存溢出

目录 1.排查方式2.结论3.解决办法 前言&#xff1a;在生产环境中有一个后端程序多次报oom然后导致程序中断。 1.排查方式 通过下载后端程序产生的oom文件&#xff0c;将oom文件导入MemoryAnalyzer程序分析程序堆内存使用情况。 1、将oom文件导入MemoryAnalyzer后可以看到概览信…...

前端开发的观察者模式

什么是观察者设计模式 观察者模式&#xff08;Observer Pattern&#xff09;是前端开发中常用的一种设计模式。它定义了一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生改变时&#xff0c;其所有依赖对象都能收到通知并自动更新。观察者模式广泛应用于事件驱动的系…...

Pycharm 输入三个引号没有自动生成函数(方法)注释

配置项路径&#xff1a;pycharm–>Settins–>Tools–>Python Integrated Tools–>Docstrings–>Docstrings format选择对应的工程&#xff0c;如果有多个工程的话将 Docstrings format 的值从 Plain 换成 reStructuredText...

lammps后处理:多帧孔洞体积和孔隙率的计算

本文介绍lammps后处理技巧:多帧孔洞体积和孔隙率的计算方法。 在前面的专栏中,已经介绍了单帧孔洞体积的计算方法,有不少粉丝朋友咨询多帧孔洞体积的计算方法。 在上一次案例代码的基础上,稍加修改,添加一个for循环遍历所有的帧即可实现多帧孔洞体积的计算。 计算的结果…...

免费且实用:UI设计常用的颜色参考网站和一些Icon设计网站

用心去分享&#xff01;请给我点个关注和点赞收藏&#xff01;谢谢各位努力的人才&#xff01; 1.在UI设计的时候&#xff0c;没有灵感&#xff0c;怎么办&#xff1f;可以参考这个网站&#xff08;需要魔法能量&#xff09; 网址如下&#xff1a; Color Hunt - Color Palette…...

log4j日志封装说明—slf4j对于log4j的日志封装-正确获取调用堆栈

日志是项目中必用的东西&#xff0c;日志产品里最普及应该就是log4j了。(logback这里暂不讨论。) 先看一下常用的log4j的用法&#xff0c;一般来说log4j都会配合slf4j或者common-logging使用&#xff0c;这里已slf4j为例。添加gradle依赖&#xff1a; dependencies { compile(l…...

JVM面试真题总结(六)

文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 文章收录在网站&#xff1a;http://hardyfish.top/ 解释GC的标记-整理算法及其优点 GC&#xff08;垃圾收集&#xff…...

C语言代码练习(第十八天)

今日练习&#xff1a; 48、猴子吃桃问题。猴子第1天摘下若干个桃子&#xff0c;当即吃了一半&#xff0c;还不过瘾&#xff0c;又多吃了一个。第2天早上又将剩下的桃子吃掉一半&#xff0c;又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时&…...

linux上使用rpm的方式安装mysql

1.从mysql官网上下载需要的版本&#xff0c;根据操作系统版本&#xff0c;CPU架构&#xff0c;下载让rpm bundle,这个版本是个完整版&#xff0c;包含其他所有版本 上传到服务器的一个目录&#xff0c;进行解压 执行tar -xvf mysql*.tar tar -xvf mysql*.tar 2.卸载老版本m…...

html 中如何使用 uniapp 的部分方法

示例代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><…...

Samtec连接器小课堂 | 连接器电镀常识QA

【摘要/前言】 像大多数电子元件一样&#xff0c;无数子元件和工艺的质量直接影响到成品的质量和性能。对于PCB级连接器&#xff0c;这些因素包括针脚材料、塑料类型、模制塑料体的质量、尾部的共面性、表面处理&#xff08;电镀&#xff09;的质量、选择正确的连接器电镀、制…...

大模型备案全网最详细流程解读(附附件+重点解读)

文章目录 一、语料安全评估 二、黑盒测试 三、模型安全措施评估 四、性能评估 五、性能评估 六、安全性评估 七、可解释性评估 八、法律和合规性评估 九、应急管理措施 十、材料准备 十一、【线下流程】大模型备案线下详细步骤说明 十二、【线上流程】算法备案填报…...

基于2143规则编码的uint8_t如何转换成float

2143格式存储的float类型数据在解码时&#xff0c;需要将1和2互换&#xff0c;3和4互换&#xff0c;然后 通过数组转float&#xff0c;进行转换 uint8_t data[] {0x72, 0x02, 0xc8, 0x42}; // 字节数组 float bytesToFloat(uint8_t data[]) { uint32_t x; memcpy(&x, da…...

[项目][WebServer][整体框架设计]详细讲解

目录 0.框架 && 前言1.TcpServer类1.功能2.类设计 2.HttpServer类1.功能2.类设计 3.Request类 && Response类1.功能2.Request类设计3.Response类设计 4.EndPoint类1.功能2.类设计 5.Task类1.功能2.类设计 6.ThreadPool类1.功能2.类设计 0.框架 && 前言…...

SprinBoot+Vue网上购物商城的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…...

【数据结构】2——二叉树遍历

数据结构2——二叉树遍历 单纯记录 文章目录 数据结构2——二叉树遍历一、二叉树遍历1&#xff0c;先序遍历&#xff1a;根左右递归实现非递归实现&#xff08;栈&#xff09; 2.中序遍历&#xff1a;左根右递归非递归 3 .后序遍历&#xff1a;左右根递归非递归&#xff08;两…...

数据结构应用实例(五)——关键路径

Content: 一、问题描述二、算法思想三、代码实现四、小结 一、问题描述 设计实现 AOE 网的关键活动与关键路径问题&#xff1b; 二、算法思想 获取拓扑序列&#xff1b;计算节点的最早开始时间 v e [ i ] ve[i] ve[i]&#xff1b;计算节点的最晚开始时间 v l [ j ] vl[j] v…...

组播 2024 9 11

PIM&#xff08;Protocol Independent Multicast&#xff09;是一种常用的组播路由协议&#xff0c;其独立于底层的单播路由协议&#xff0c;能够在多种网络环境中有效地实现多播路由功能。PIM主要有两种模式&#xff1a;PIM Sparse Mode (PIM-SM) 和 PIM Dense Mode (PIM-DM)&…...

揭秘开发者的效率倍增器:编程工具的选择与应用

文章目录 每日一句正能量前言工具介绍功能特点&#xff1a;使用场景&#xff1a;提高工作效率的方式&#xff1a; 效率对比未来趋势后记 每日一句正能量 这推开心窗之人&#xff0c;可以是亲朋好友&#xff0c;也可以是陌客路人&#xff0c;可以是德高望重的哲人名流&#xff0…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)

骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术&#xff0c;它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton)&#xff1a;由层级结构的骨头组成&#xff0c;类似于人体骨骼蒙皮 (Mesh Skinning)&#xff1a;将模型网格顶点绑定到骨骼上&#xff0c;使骨骼移动…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝

目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为&#xff1a;一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...