图论 之 迪斯科特拉算法求解最短路径

news2025/2/23 0:13:42

文章目录

  • 题目
    • 743.网络延迟时间
    • 3341.到达最后一个房间的最少时间I

求解最短路径的问题,分为使用BFS和使用迪斯科特拉算法,这两种算法求解的范围是有区别的

  • BFS适合求解,边的权值都是1的图中的最短路径的问题
    图论 之 BFS
  • 迪斯科特拉算法适合求解边的权值不一样的图,其中,该算法有两种实现方式,分别适用于两种情况的图
    • 稠密图,使用朴素的Dijkstra算法,其中稠密图的定义是,边的数量级与 o ( n 2 ) o(n^2) o(n2)相当的图,朴素的Dijkstra算法的时间复杂度是 o ( n 2 ) o(n^2) o(n2),其中n是图的节点的数量
    • 稀疏图,使用堆优化的Dijkstra算法,算法的时间复杂度是 o ( m l o g m ) o(mlogm) o(mlogm)其中,m是边的数量,如果输入的稠密图,那么使用堆优化的Dijkstra算法的时间复杂度是 o ( n 2 l o g n ) o(n^2logn) o(n2logn)

朴素的Dijkstras算法的模版

# 存储边的情况
edge = [[float('inf')]*n for n in range(n)]
# dis[i]表示 单源点k到其余节点i的最短的路径
dis = [float('inf')]*n 
dis[k] = 0
# 这个done[k] = True不用设置,后面会依据这个,把起点弹出
done = [False]*n # done[i]标记是否找到 到达节点i的最短的路径

while True:
	x = -1
	for i,ok in enumerate(done):
		# 找到在还没确定最小距离的节点,该节点到源点的距离最小
		if not ok and (x < 0 or dis[i] < dis[x]):
			x = i
	# 判断是否都找到了
	if x < 0:
		# 这里就已经求解完成了,后续你可以返回最大值?
		return dis
	# 有节点无法到达
	if dis[x] == float('inf'):
		return -1
	# 设置标志位,表示节点x的最小距离已经确定
	done[x] = True
	# 遍历当前节点的所有的邻居,更新答案
	for j,d in enumerate(edge[x]):
		dis[j] = min(dis[j],dis[j]+d)
		

使用堆优化的Dijkstra算法


import heapq

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        # 使用堆优化的Dijkstra算法
        # 使用堆优化的话,适用于稀疏图,所以边的记录,我们使用邻接表
        edge = [[] for _ in range(n)]
        for x,y,z in times:
            edge[x-1].append((y-1,z))
        
        dis = [float('inf')]*n 
        dis[k-1] = 0
        # 入堆的元素是 (dis[x],x),第一个元素是距离,这也是设置的优先级
        h = [(0,k-1)]
        while h:
        	# 出堆
            dx,x = heapq.heappop(h)
            # 如果当前的距离大于最小距离,直接过
            if dx > dis[x]:
                # 说明之前出过堆
                continue
            # 访问邻居,不一定是这个邻接表或者邻接矩阵,二维表也可以
            for y,d in edge[x]:
            	# 计算更新值,计算方式按照题目的意思
                new_dis = dx + d 
                # 只有更优的值才能被加入进去
                if new_dis < dis[y]:
                    dis[y] = new_dis
                    heapq.heappush(h,(new_dis,y))
        mx = max(dis)
        return mx if mx < float('inf') else -1

题目

743.网络延迟时间

743.网络延迟时间

在这里插入图片描述

在这里插入图片描述

思路分析:由于边的数量远远大于节点的数量,所以我们还是考虑使用稠密图下的朴素的Dijkstra算法,最后返回不是无穷的最大的路径即可

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        # 区别于BFS求解的最短距离,这个距离的边的权值不一样
        # 使用朴素的迪斯科特拉算法

        # 邻接矩阵记录边的情况
        edge = [[float('inf')]*(n) for _ in range(n)]
        # 有向边
        for e in times:
            edge[e[0]-1][e[1]-1] = e[2]
        
        dis = [float('inf')]*n # 记录k到各个节点的最短距离
        ans = dis[k-1] = 0
        done = [False] * n # 记录节点的最短距离是否被确定
        while True:
            x = -1
            # 找到最短距离还没确定,并且节点k到它的距离是最短的节点
            for i,ok in enumerate(done):
                if not ok and (x<0 or dis[i] < dis[x]):
                    x = i 
            # 如果x<0,表示全部的节点已经全部都访问过了
            if x < 0 :
                return ans
            # 如果最短的节点的距离是无穷,说明不可达
            if dis[x] == float('inf'):
                return -1
            # 更新
            ans = dis[x]
            done[x] = True
            for y,d in enumerate(edge[x]):
                dis[y] = min(dis[y],dis[x]+d)

使用堆优化的解法

import heapq

class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        # 使用堆优化的Dijkstra算法
        # 使用堆优化的话,适用于稀疏图,所以边的记录,我们使用邻接表
        edge = [[] for _ in range(n)]
        for x,y,z in times:
            edge[x-1].append((y-1,z))
        
        dis = [float('inf')]*n 
        dis[k-1] = 0
        # 入堆的元素是 (dis[x],x)
        h = [(0,k-1)]
        while h:
            dx,x = heapq.heappop(h)

            if dx > dis[x]:
                # 说明之前出过堆
                continue
            for y,d in edge[x]:
                new_dis = dx + d 
                if new_dis < dis[y]:
                    dis[y] = new_dis
                    heapq.heappush(h,(new_dis,y))
        mx = max(dis)
        return mx if mx < float('inf') else -1

3341.到达最后一个房间的最少时间I

3341.到达最后一个房间的最少时间I

在这里插入图片描述

思路分析:开始的时候,我错误的以为题目中只能向右或者向下运动, 所以写了一个动态规划进行求解,实际上,这个思路是错误的,不过要是只能向下或者向右运动的话,动态规划也是一种很好的做法

# 动态规划的做法,竟然可以过700个测试用例
import heapq
class Solution:
    def minTimeToReach(self, moveTime: List[List[int]]) -> int:
        # 开始的时候从(0,0)出发,移动到相邻的房间,其实也只是向下或向右运动
        # 感觉可以用动态规划,dp[i][j]表示到达i,j所需的最少的时间
        # 递推公式,
        # dp[i][j] = min(max(dp[i-1][j],moveTime[i][j])+1,max(dp[i][j-1],moveTime[i][j])+1)
        n = len(moveTime)
        m = len(moveTime[0])
        dp = [[float('inf')]*(m+1) for _ in range(n+1)]
        dp[1][1] = 0
        for i in range(n):
            for j in range(m):
                if i == 0 and j == 0:
                    continue
                dp[i+1][j+1] = min(max(dp[i][j+1],moveTime[i][j])+1,max(dp[i+1][j],moveTime[i][j])+1)
        for i in dp:
            print(i )

        return dp[n][m]

正确的思路:应该是使用Dijkstra算法,不过开始的时候,我有点纠结这个edge也就是边的矩阵如何转化为邻接矩阵或者邻接表,后面一想,还是我的固定思维阻碍了我,邻接矩阵和邻接表只是一个工具,帮助我们找到当前的节点的邻居,但是在现在的图中,你通过坐标的加减不就可以得到对应的邻居嘛!

  • 展示使用朴素Dijkstra算法做法
import heapq
class Solution:
    def minTimeToReach(self, moveTime: List[List[int]]) -> int:
        # 首先先使用 堆优化的Dijkstra进行解题
        # 图已经构建,就是moveTime
        # dis[i][j]表示(0,0)到(i,j)的最短的时间
        n,m = len(moveTime),len(moveTime[0])
        dis = [[float('inf')]*m for _ in range(n)]
        dis[0][0] = 0
        done = [[False]*m for _ in range(n)]
        while True:
            x,y = -1,-1
            # 开始遍历还没确定的点
            for i in range(n):
                for j in range(m):
                    if not done[i][j] and ((x<0 and y <0) or dis[i][j] < dis[x][y]):
                        x,y = i,j
            if x<0 and y <0:
                # 说明都找到了
                return dis[n-1][m-1]
            
            # 设置已经找到
            done[x][y] = True
            # 访问邻居
            for i,j in (x+1,y),(x-1,y),(x,y+1),(x,y-1):
                if 0<= i < n and 0<= j < m:
                    dis[i][j] = min(max(dis[x][y],moveTime[i][j]) + 1,dis[i][j])


  • 展示使用堆优化的Dijkstra算法
import heapq
class Solution:
    def minTimeToReach(self, moveTime: List[List[int]]) -> int:
        # 首先先使用 堆优化的Dijkstra进行解题
        # 图已经构建,就是moveTime
        # dis[i][j]表示(0,0)到(i,j)的最短的时间
        n,m = len(moveTime),len(moveTime[0])
        dis = [[float('inf')]*m for _ in range(n)]
        dis[0][0] = 0
        h = [(0,0,0)]

        while True:
            d,x,y = heapq.heappop(h)
            if x == n-1 and y == m-1:
                return d 
            # 已经更新过了
            if d > dis[x][y]:
                continue
            
            # 访问邻居:
            for i,j in (x+1,y),(x-1,y),(x,y+1),(x,y-1):
                if 0<= i <n and 0<= j < m:
                    # 合法的坐标
                    # 计算当前的距离,小于才入堆
                    new_dis = max(d,moveTime[i][j])+1
                    if dis[i][j]>new_dis:
                        dis[i][j] = new_dis
                        heapq.heappush(h,(dis[i][j],i,j))

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

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

相关文章

Spring Boot 中事务的用法详解

引言 在 Spring Boot 中&#xff0c;事务管理是一个非常重要的功能&#xff0c;尤其是在涉及数据库操作的业务场景中。Spring 提供了强大的事务管理支持&#xff0c;能够帮助我们简化事务的管理和控制。本文将详细介绍 Spring Boot 中事务的用法&#xff0c;包括事务的基本概…

【react18】如何使用useReducer和useContext来实现一个todoList功能

重点知识点就是使用useReducer来攻坚小型的公共状态管理&#xff0c;useImmerReducer来实现数据的不可变 实现效果 实现代码 项目工程结构 App.js文件 import logo from "./logo.svg"; import "./App.css"; import TodoLists from "./comps/TodoLi…

一篇搞懂vue3中如何使用ref、reactive实现响应式数据

ref 可实现 基本类型、对象类型响应式数据 reactive&#xff1a;只能实现 对象类型响应式 ref实现 基本类型 数据响应式&#xff1a; <template><div class"person"><h2>姓名&#xff1a;{{ name }}</h2><h2>年龄&#xff1a;{{ ag…

【HeadFirst系列之HeadFirst设计模式】第7天之命令模式:封装请求,轻松实现解耦!

命令模式&#xff1a;封装请求&#xff0c;轻松实现解耦&#xff01; 大家好&#xff01;今天我们来聊聊设计模式中的命令模式&#xff08;Command Pattern&#xff09;。如果你曾经需要将请求封装成对象&#xff0c;或者希望实现请求的撤销、重做等功能&#xff0c;那么命令模…

Linux-Ansible自动化运维

文章目录 自动化运维Ansible &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Linux专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年02月21日17点38分 自动化运维 自动化运维常用工具 Ansible 和 SaltStack 自动化运维优势&#xff1a; 服…

uni-app(位置1)

文章目录 一、获取当前的地理位置、速度 uni.getLocation(OBJECT)二、打开地图选择位置 uni.chooseLocation(OBJECT)三、使用应用内置地图查看位置。uni.openLocation(OBJECT) 一、获取当前的地理位置、速度 uni.getLocation(OBJECT) App平台 manifest中配置好自己的地图厂商k…

RabbitMQ服务异步通信

消息队列在使用过程中&#xff0c;面临着很多实际问题需要思考&#xff1a; 1. 消息可靠性 消息从发送&#xff0c;到消费者接收&#xff0c;会经理多个过程&#xff1a; 其中的每一步都可能导致消息丢失&#xff0c;常见的丢失原因包括&#xff1a; 发送时丢失&#xff1a; 生…

CSS基础(浮动、相对定位、绝对定位、固定定位、粘性定位、版心、重置默认样式)

文章目录 1. 浮动&#xff08;float&#xff09;1.1 简介1.2 元素浮动后的特点1.3 脱离文档流示例图1.4 浮动产生的影响1.4.1 积极影响1.4.2 消极影响 1.5 解决浮动产生的影响1.5.1 清除浮动&#xff08;Clearfix&#xff09;1.5.2 创建新的块格式化上下文&#xff08;BFC&…

Spring Cloud — Hystrix 服务隔离、请求缓存及合并

Hystrix 的核心是提供服务容错保护&#xff0c;防止任何单一依赖耗尽整个容器的全部用户线程。使用舱壁隔离模式&#xff0c;对资源或失败单元进行隔离&#xff0c;避免一个服务的失效导致整个系统垮掉&#xff08;雪崩效应&#xff09;。 1 Hystrix监控 Hystrix 提供了对服务…

RagFlow+Ollama 构建RAG私有化知识库

RagFlowOllama 构建RAG私有化知识库 关于RAG一、什么是RAGFlow一、RAGFlow 安装配置测服已有服务&#xff1a; mysql、redis、elasticsearch 二、RAGFlow 配置 ollama&#xff1a;本地运行大型语言模型的工具软件。用户可以轻松下载、运行和管理各种开源 LLM。降低使用门槛&…

【Linux】【网络】不同子网下的客户端和服务器通信

【Linux】【网络】不同子网下的客户端和服务器通信 前两天在进行socket()网络编程并进行测试时&#xff0c;发现在不同wifi下两个电脑无法进行连接&#xff0c;大概去查找了如何解决 看到可以使用 frp 这个快速反向代理实现。 frp 可让您将位于 NAT 或防火墙后面的本地服务器…

SpringBoot教程(十四) SpringBoot之集成Redis

SpringBoot教程&#xff08;十四&#xff09; | SpringBoot之集成Redis 一、Redis集成简介二、集成步骤 2.1 添加依赖2.2 添加配置2.3 项目中使用之简单使用 &#xff08;举例讲解&#xff09;2.4 项目中使用之工具类封装 &#xff08;正式用这个&#xff09;2.5 序列化 &…

OpenHarmony分布式数据管理子系统

OpenHarmony分布式数据管理子系统 简介 目录 组件说明 分布式数据对象数据共享分布式数据服务Key-Value数据库首选项关系型数据库标准数据化通路 相关仓 简介 子系统介绍 分布式数据管理子系统支持单设备的各种结构化数据的持久化&#xff0c;以及跨设备之间数据的同步、…

单片机 Bootloade与二进制文件的生成

单片机的 Bootloader 是一种特殊的程序&#xff0c;负责在单片机上电后初始化硬件、更新用户应用程序&#xff08;固件&#xff09;&#xff0c;并将控制权移交给用户程序。以下是其运行机制和关键流程的详细说明&#xff1a; 1、单片机 Bootloader 的核心作用 固件更新&…

MySQL数据库(3)—— 表操作

目录 一&#xff0c;创建表 1.1 创建表的SQL 1.2 演示 二&#xff0c;查看表 三&#xff0c;修改表 四&#xff0c;删除表 常用的表操作会涉及到两种SWL语句 DDL&#xff08;Data Definition Language&#xff09;数据定义语言&#xff1a;建表、改表、删表等&#xff0…

Springboot + Ollama + IDEA + DeepSeek 搭建本地deepseek简单调用示例

1. 版本说明 springboot 版本 3.3.8 Java 版本 17 spring-ai 版本 1.0.0-M5 deepseek 模型 deepseek-r1:7b 需要注意一下Ollama的使用版本&#xff1a; 2. springboot项目搭建 可以集成在自己的项目里&#xff0c;也可以到 spring.io 生成一个项目 生成的话&#xff0c;如下…

七星棋牌源码高阶技术指南:6端互通、200+子游戏玩法深度剖析与企业级搭建实战(完全开源)

在棋牌游戏行业高速发展的今天&#xff0c;如何构建一个具备高并发、强稳定性与多功能支持的棋牌游戏系统成为众多开发者和运营团队关注的焦点。七星棋牌全开源修复版源码 凭借其 六端互通、200子游戏玩法、多省区本地化支持&#xff0c;以及 乐豆系统、防沉迷、比赛场、AI智能…

HarmonyOS 开发套件 介绍 ——上篇

HarmonyOS 开发套件 介绍 ——上篇 在当今科技飞速发展的时代&#xff0c;操作系统作为智能设备的核心&#xff0c;其重要性不言而喻。而HarmonyOS&#xff0c;作为华为推出的全新操作系统&#xff0c;正以其独特的魅力和强大的功能&#xff0c;吸引着越来越多的开发者和用户的…

网络空间安全(1)web应用程序的发展历程

前言 Web应用程序的发展历程是一部技术创新与社会变革交织的长卷&#xff0c;从简单的文档共享系统到如今复杂、交互式、数据驱动的平台&#xff0c;经历了多个重要阶段。 一、起源与初期发展&#xff08;1989-1995年&#xff09; Web的诞生&#xff1a; 1989年&#xff0c;欧洲…

JUC并发—9.并发安全集合三

大纲 1.并发安全的数组列表CopyOnWriteArrayList 2.并发安全的链表队列ConcurrentLinkedQueue 3.并发编程中的阻塞队列概述 4.JUC的各种阻塞队列介绍 5.LinkedBlockingQueue的具体实现原理 6.基于两个队列实现的集群同步机制 1.并发安全的数组列表CopyOnWriteArrayList …