代码随想录算法训练营第五十九天 | dijkstra(堆优化版)精讲

news2024/11/18 9:28:49

目录

dijkstra(堆优化版)精讲

思路

堆优化细节

方法一: 最小堆优化


dijkstra(堆优化版)精讲

  • 题目链接:卡码网:47. 参加科学大会
  • 文章讲解:代码随想录 

小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。

小明的起点是第一个车站,终点是最后一个车站。然而,途中的各个车站之间的道路状况、交通拥堵程度以及可能的自然因素(如天气变化)等不同,这些因素都会影响每条路径的通行时间。

小明希望能选择一条花费时间最少的路线,以确保他能够尽快到达目的地。

【输入描述】

第一行包含两个正整数,第一个正整数 N 表示一共有 N 个公共汽车站,第二个正整数 M 表示有 M 条公路。

接下来为 M 行,每行包括三个整数,S、E 和 V,代表了从 S 车站可以单向直达 E 车站,并且需要花费 V 单位的时间。

【输出描述】

输出一个整数,代表小明从起点到终点所花费的最小时间。

输入示例

7 9
1 2 1
1 3 4
2 3 2
2 4 5
3 4 2
4 5 3
2 6 4
5 7 4
6 7 9

输出示例:12

【提示信息】

能够到达的情况:

如下图所示,起始车站为 1 号车站,终点车站为 7 号车站,绿色路线为最短的路线,路线总长度为 12,则输出 12。

不能到达的情况:

如下图所示,当从起始车站不能到达终点车站时,则输出 -1。

数据范围:

1 <= N <= 500; 1 <= M <= 5000

思路

堆优化细节

其实思路依然是 dijkstra 三部曲:

  1. 第一步,选源点到哪个节点近且该节点未被访问过
  2. 第二步,该最近节点被标记访问过
  3. 第三步,更新非访问节点到源点的距离(即更新minDist数组)

只不过之前是 通过遍历节点来遍历边,通过两层for循环来寻找距离源点最近节点。 这次我们直接遍历边,且通过堆来对边进行排序,达到直接选择距离源点最近节点。

先来看一下针对这三部曲,如果用 堆来优化。

那么三部曲中的第一步(选源点到哪个节点近且该节点未被访问过),我们如何选?

我们要选择距离源点近的节点(即:该边的权值最小),所以 我们需要一个 小顶堆 来帮我们对边的权值排序,每次从小顶堆堆顶 取边就是权值最小的边。

pq中中为什么要存 源点到该节点的权值,因为 这个小顶堆需要按照权值来排序)

有了小顶堆自动对边的权值排序,那我们只需要直接从 堆里取堆顶元素(小顶堆中,最小的权值在上面),就可以取到离源点最近的节点了 (未访问过的节点,不会加到堆里进行排序)

所以三部曲中的第一步,我们不用 for循环去遍历,直接取堆顶元素:

# 1. 第一步,选源点到哪个节点近且该节点未被访问过 (通过优先级队列来实现)
# 节点, 源点到该节点的距离
cur_dict,cur_node = heapq.heappop(pq)

第二步(该最近节点被标记访问过) 这个就是将 节点做访问标记,和 朴素dijkstra 一样 ,代码如下:

# 2. 第二步,该最近节点被标记访问过
visited[cur_node] = True

cur.first 是指取 pair<int, int> 里的第一个int,即节点编号 )

第三步(更新非访问节点到源点的距离),这里的思路 也是 和朴素dijkstra一样的。

但很多录友对这里是最懵的,主要是因为两点:

  • 没有理解透彻 dijkstra 的思路
  • 没有理解 邻接表的表达方式

我们来回顾一下 朴素dijkstra 在这一步的代码和思路(如果没看过我讲解的朴素版dijkstra,这里会看不懂)

# 3、第三步,更新非访问节点到源点的距离(即更新minDist数组)
for j in range(1,n+1):
    if not visited[j] and graph[cur][j] != float('inf') and graph[cur][j] + minDist[cur] < minDist[j]:
        minDist[j] = minDist[cur] + graph[cur][j]

其中 for循环是用来做什么的? 是为了 找到 节点cur 链接指向了哪些节点,因为使用邻接矩阵的表达方式 所以把所有节点遍历一遍。

而在邻接表中,我们可以以相对高效的方式知道一个节点链接指向哪些节点。

所以在邻接表中,我们要获取 节点cur 链接指向哪些节点,就是遍历 graph[cur节点编号] 这个链表。

接下来就是更新 非访问节点到源点的距离,代码实现和 朴素dijkstra 是一样的,代码如下:

for edge in edges[cur_node]:
    if not visited[edge.to] and cur_dict + edge.val < minDist[edge.to]:
        minDist[edge.to] = cur_dict + edge.val
        heapq.heappush(pq,(minDist[edge.to],edge.to))

方法一: 最小堆优化

import heapq
import sys
class Edge:
    def __init__(self,to,val) -> None:
        self.to = to 
        self.val = val

def dijkstra(edges,n,start,end):
    visited = [False] * (n+1)
    minDist = [float('inf')] * (n+1)
    minDist[start] = 0

    pq = []
    heapq.heappush(pq,(0,start))
    while pq:
        cur_dict,cur_node = heapq.heappop(pq)

        if visited[cur_node]:
            continue

        visited[cur_node] = True

        for edge in edges[cur_node]:
            if not visited[edge.to] and cur_dict + edge.val < minDist[edge.to]:
                minDist[edge.to] = cur_dict + edge.val
                heapq.heappush(pq,(minDist[edge.to],edge.to))

    return -1 if minDist[end] == float('inf') else minDist[end]
if __name__=="__main__":
    input = sys.stdin.read
    data = input().split()

    # n个车站,m条公路
    n = int(data[0])
    m = int(data[1])

    edges = [[] for i in range(n+1)]

    index = 2

    for i in range(m):
        start = int(data[index])
        to = int(data[index+1])
        val = int(data[index+2])
        edges[start].append(Edge(to,val))
        index += 3

    res = dijkstra(edges,n,start=1,end=n)

    print(res)

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

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

相关文章

MySQL 事务的 ACID 特性与应用

MySQL事务的ACID特性与应用 数据库事务 是保障数据一致性和完整性的关键机制。事务不仅是并发控制的核心&#xff0c;更是数据恢复的基本单位。本文将带你深入了解MySQL中的事务概念、ACID特性以及如何在实际应用中正确处理事务。 1. 什么是事务&#xff1f; 事务&#xff0…

基于Vue的兴趣活动推荐APP的设计与实现_kaic

摘 要 近年来&#xff0c;随着互联网不断的普及与发展&#xff0c;生活也变的多姿多彩&#xff0c;每个人几乎都有属于自己的小小兴趣圈子&#xff0c;但人们的兴趣却不止一个&#xff0c;大多数人是没有时间为自己的兴趣“买单”的。为了解决我们在生活中对于各种兴趣活动的…

学习笔记缓存篇(一)

1、如何解决热key 1、本地缓存 采用本地缓存的优点在于简单&#xff0c;扩容方便。但是会带来一致性的问题。 2、离散热点key 做法&#xff1a;结合当前节点的ip或者机器的MAC地址去得出一个固定值拼接在key后面。访问时也是根据key&#xff0c;到后端固定的edis上。 优点&…

学习结构体的使用

对于结构体的创建&#xff0c;首先要创建一个结构体类型&#xff0c;像下面这样&#xff1a; 结构体对成员的访问&#xff0c;就是变量名.成员就可以了 当然对于结构体的声明还有一些特殊的声明 结构体的自引用 结构体的重命名

Linux 35.5 + JetPack v5.1.3@CUDA安装和版本切换

Linux 35.5 JetPack v5.1.3CUDA安装和版本切换 1. 源由2. 现象3. 分析3.1 看本质3.2 善动脑3.3 笔记回忆3.4 底层思考3.5 多版本 4. 版本切换5. 总结 1. 源由 最近遇到一些CUDA编程&#xff0c;以及编译链接过程出现一些版本不匹配的问题。 首先&#xff0c;申明下&#xff…

【网络安全的神秘世界】渗透测试基础

&#x1f31d;博客主页&#xff1a;泥菩萨 &#x1f496;专栏&#xff1a;Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 渗透测试基础 基于功能去进行漏洞挖掘 1、编辑器漏洞 1.1 编辑器漏洞介绍 一般企业搭建网站可能采用了通用模板&#xff…

神经网络的公式推导与代码实现(论文复现)

神经网络的公式推导与代码实现&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 概述 本文将详细推导一个简单的神经网络模型的正向传播、反向传播、参数更新等过程&#xff0c;并将通过一个手写数字识别的例子&#xff0c;使用python手写和pytorch…

充电管理芯片

1.接口 typec SBU引脚&#xff08;辅助通道&#xff09; SBU引脚是Type-C接口母座中的辅助通道&#xff0c;用于支持附加的功能&#xff0c;如模拟音频和视频传输。通过SBU引脚&#xff0c;Type-C接口母座可以实现更广泛的连接应用&#xff0c;包括连接到外部显示器、音频设备…

【前端】main.js中app.vue中 render函数的作用及使用背景

vue.js中的main.js中的作用是将app组件挂载到页面中&#xff0c;其中app组件是汇总所有组件元素的组件。main.js的创建vue实例。 #认为的版本 import APP from ./App.vue;new Vue({el:#root,template:<App></App>,components:{App}, })#实际的版本 /* 整个项目的入…

基于imx6ull平台opencv的图像采集和显示屏LCD显示功能(带Qt界面)

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 验证功能一、概述 本文档是针对imx6ull平台opencv的图像采集和显示屏LCD显示功能,创建Qt工程,在工程里面通过点击按钮,实现opencv通过摄像头采集视频图像,将采集的视频图像送给显示屏LCD进…

docker-compose elasticsearch 集群搭建(用户登录+https访问)

文章目录 前言docker-compose elasticsearch 集群搭建(用户登录+https访问)1. 效果2. 制作elasticsearch + 分词器镜像2.1. 拉取elasticsearch:7.11.12.2. 制作特定版本镜像3. docker-compose elasticsearch 集群制作4. es账户密码初始化前言 如果您觉得有用的话,记得给博主点…

<Python>基于python使用PyQt6编写一个延迟退休计算器

前言 这两天关于延迟退休的话题比较火&#xff0c;官方也退出了延迟退休计算器的小程序&#xff0c;我们使用python来实现一个。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;python 库&#xff1a;pyqt6 程序依据 程序的算法依据…

常见本地大模型个人知识库工具部署、微调及对比选型

文章目录 常见本地大模型个人知识库工具部署、微调及对比选型知识库侧AnythingLLMMaxKBRAGFlowFastGPTDifyOpen WebUI小结大模型侧OllamaLM StudioXinference小结大模型侧工具安装部署实践Ollama部署Windows部署OllamaLinux部署OllamaOllama使用技巧模型更换存储路径导出某个模…

外国车牌字符识别与分类系统源码分享

外国车牌字符识别与分类检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Co…

【Java面试】第九天

&#x1f31f;个人主页&#xff1a;时间会证明一切. 目录 Spring中如何开启事务&#xff1f;编程式事务声明式事务声明式事务的优点声明式事务的粒度问题声明式事务用不对容易失效 Spring的事务传播机制有哪些&#xff1f;Spring事务失效可能是哪些原因&#xff1f;代理失效的情…

Ubuntu下beanstalkd无法绑定局域网IP地址以及消息队列beanstalkd上的error: JOB_TOO_BIG的解决

一、ubuntu下beanstalkd无法绑定局域网IP地址 今天因为业务需要&#xff0c;我把之前安装的beanstalkd所绑定的IP地址由127.0.0.1改成局域网IP地址&#xff0c;但是怪了&#xff0c;显示beanstalkd已经启动&#xff0c;查看端口监控也显示IP地址变了&#xff0c;但是使用telnet…

matlab绘制不同区域不同色彩的图,并显示数据(代码)

绘图结果如下&#xff1a; 代码如下&#xff1a; A为绘图的数据&#xff0c;每个数据对应着上图中的一个区域&#xff0c;数据大小决定区域的颜色 % 假设有一系列的数据点 Arand(5,6); %A为绘图的数据&#xff0c;数据大小决定颜色 wei_shu%.3f; %代表数据保留三位小…

[Golang] Channel

[Golang] Channel 文章目录 [Golang] Channel什么是Channelchannel的初始化channel的操作双向channel和单向channel为什么有channel有缓冲channel和无缓冲channlechannel做一把锁 从之前我们知道go关键字可以开启一个Goroutine&#xff0c;但是Goroutine之间的通信还需要另一个…

Recyclerview实现滑动居中缩放菜单

最近项目中需要的一个滑动菜单效果:要求当前居中选项放大、滑动时有缩放效果、点击两边的选项滑动到屏幕中央、停止滑动选项停留在屏幕中间(类似viewPager的效果),为了直观,先上最终实现效果图: 大体思路: Recyclerview item头尾添加空数据,让第一个和最后一个item也能…

计算机组成原理(第二次笔记)

各种码 真值 (书写用)&#xff1a; 将用“”、“-” 表示正负的二进制数称为真值 机器不能识别书写格式&#xff0c;故用“0/1”表示“/-”符号。 机器码 (机器内部使用)&#xff1a; 将符号和数值一起编码表示的二进制数称为机器码。 常用机器码&#xff1a;原码、 反码、 补…