最短路径问题(图论)

1 Floyd

作用:

求图中所有顶点之间的最短路径,包括有向图或者无向图,权重正负皆可,用来一次性求所有点之间的最短路径。
思路是 通过逐步扩大中间层,使得最短路径不断被更新,直到中间层扩大到n位置,最终所求的就是所有节点都有可能经过的最短距离。

原理

  • 递推公式,F[K][X][Y] 表示顶点x,y中间最多只经过(0,1,2,…k)这些顶点时的最短路径
    在这里插入图片描述

  • 三层遍历,第一层必须为中间层,这样才会逐步将中间层扩大,如果中间层没有放在第一层,会导致 每个f[x] 实际只会求取一次,结果不正确。

  • **根据上面实际上需要使用三位数组进行求解,但是可以优化为二维数组,初始状态时,时候F[X][Y]可能为 “0/实际权重/正无穷”;如果点X,Y直连,则F[X][Y]为实际权重;如果点X==Y,则F[X][Y]=0;如果点X,Y非直连,则F[X][Y] = 正无穷

实际的代码如下:

for k in range(1, n + 1):for x in range(1, n + 1):for y in range(1, n + 1):f[k][x][y] = min(f[k - 1][x][y], f[k - 1][x][k] + f[k - 1][k][y])

最外层的数组可以省略,优化为如下:

for k in range(1, n + 1):for x in range(1, n + 1):for y in range(1, n + 1):f[x][y] = min(f[x][y], f[x][k] + f[k][y])

详见 Floyd算法解析

2 Dijsktra算法

作用

是一种单源最短路径算法,他能找到其中一个点到其他所有点的最短路径,只支持权重为正的情况, 因为Dijkstra算法存在贪心的策略,一旦到某个节点的最短路径被确定,后续就无法修改。故无法支持权重为负的情,其基本的实现策略为贪心+动态更新,
思路:每一步都是从还未处理的节点当中找到离起点最短的节点,然后尝试用它来更新其周围邻居离起点的最短路径,这样一步步扩展,直到找到最短路径。

实现原理

假设有如下图结构,求节点A到节点F的最短距离,实现过程如下:

  • 首先准备一个优先队列,一个最短距离前驱表t1,以及visisted存放是否已经i经访问过。t1[v] = (d, v1)表示顶点A距离顶点v的最短距离d以及顶点v的前驱节点v1,初始的时候,将顶点A到它自身的距离为0,其他顶点到顶点A的距离为无穷大,前驱节点为空,将(0,A)放到优先队列中(以第一位距离作为排序的key,小根堆)
    在这里插入图片描述
  • 首先从优先队列中取出首位距离最短的节点信息(0, A),然后依次遍历顶点A的所有边(B,C),将(4, B),(5,C)放到优先队列中,同时更新最短距离前驱表,并将顶点A放到visited表,表示下次遍历到顶点A的时候,直接忽略,具体结果如下:
    在这里插入图片描述
  • 然后再从优先队列中取出顶点(4, B)信息,依次遍历B所有的边(C, D,E)其中A已经被放到visited中,无需再遍历,遍历B的边C的时候,发现权重之和(A->B + B->C =4 + 11 < 5)大于当前表中已经存在的距离,故这里不更新C的距离以及前驱;遍历边D的时候,发现(A->B + B-> = 4 + 9 = 13 < 正无穷 )小于当前表中已经存在,更细表中顶点D到A的最短距离为13以及前驱节点为B。
  • 后续的操作与上面一样,直到优先队列中的元素被取完在优先队列中提前碰到目标节点,如果从优先队列中取出的顶点到A的距离小于表中已经存在的距离或者已经处于visited表中,则直接忽略即可
  • 最后通过得到的最短距离前驱表可以得到顶点A到其他所有节点的最短距离以及对应的路径
  • 如果只需要求起点到某个终点的最短路径,则可以在优先队列中取到目标终点时,可以直接返回,无需再往下处理

备注:最短距离前驱表中前驱信息是用来根据回溯得到目标顶点的最短路径
代码实现

def dijkstra(n, source, weights):## weights 列表的每一个元素格式为(n1, n2, w)表示顶点n1->n2的权重为w## n 表示顶点的格式,source表示原顶点## 这里需要将顶点信息都转化为0,1... n-1的编号# 为求顶点source 到其他顶点的最短距离neighbors = [[] for _ in range(n)]inf = float('inf')edges = [[inf for _ in range(n)] for _ in range(n)]for v1, v2, w in weights:neighbors[v1].append(v2)neighbors[v2].append(v1)edges[v1][v2] = wedges[v2][v1] = wpq = []heapq.heappush(pq, (0, source))visited = set()t1 = {}for i in range(n):t1[i] = (inf, -1)t1[source] = (0, -1)while pq:d, v = heapq.heappop(pq)if d > t1[v][0]:continuevisited.add(v)for p in neighbors[v]:d1 = d + edges[v][p]if p not in visited and (d1 < t1[p][0]):t1[p] = (d1, v)heapq.heappush(pq, (d1, p))return t1if __name__ == '__main__':n = 6source = 0weights = [[0, 1, 4], [0, 2, 5], [1, 2,11], [1, 3, 9], [1, 4, 7], [2, 4, 3], [3, 4, 13], [3, 5, 2], [4, 5, 6]]print(dijkstra(6, 0, weights))

3 Bellman-Ford算法

作用

上面的dijkstra算法只支持权重为正场景,对于有些权值为负的场景需要使用BellmanFord算法,该算法也是求单个顶点到到其余顶点的最短路径,如果存在负环路径,则不存在最短路径
思路:通过不断的遍历所有的边动态的更新到起点的最短距离,不断地进行松紧操作(迭代),直到n - 1次,确保所有节点到起点均是最短距离。

实现原理

假设有如下图结构,求节点A到其他节点的最短距离,实现过程如下
在这里插入图片描述

  • 首先需要准备一个最短路径前驱表t1, t1[v] 中包含顶点v到顶点A的最短距离以及顶点v的前驱节点。初始的时候 t1[‘A’] = (0, -1) 其他的t[v] = (正无穷,-1)
  • 然后遍历所有的边,每遍历一个边(v1, v2)的时候,如果当前节点A到v1的t1[v1][0] + 当前边的权重w(v1->v2)小于当前t1[v2][0],则更新v2的最短距离以及前驱节点
    t1[v1][0] + w(v1->v2) < t1[v2][0]
  • 上面的步骤最多执行n - 1次,如果中间有一次 没有节点的最短距离需要更新,则说明所有A到所有节点的最短距离已经全部收敛,直接返回。
  • 如果上面执行n- 1次,每次均存在节点的最短距离需要更新,则图中可能存在负权环,所谓负权环就是如下图所示,随着遍历次数的增加,A到C的距离只会越来越小-2, -3, -4等等,此时说明最短路径,那么只需要再遍历第n次,看看是否仍存在某个节点的最短路径被更新,如果被更新,则该节点存在负权环。
    在这里插入图片描述
def bellmanFord(n, source, weights):## weights 列表的每一个元素格式为(n1, n2, w)表示顶点n1->n2的权重为w## n 表示顶点的格式,source表示原顶点## 这里需要将顶点信息都转化为0,1... n-1的编号# 为求顶点source 到其他顶点的最短距离t1 = {}inf = float('inf')for i in range(n):t1[i] = (inf, -1)t1[source] = (0, -1)for i in range(n - 1):for v1, v2, w in weights:if (t1[v1][0] + w) < t1[v2][0]:t1[v2] = (t1[v1][0] + w, v1)# make sure weather negative weight loop existflag, v= False, Nonefor v1, v2, w in weights:if (t1[v1][0] + w) < t1[v2][0]:flag, v = True, v2return t1, flag, vif __name__ == '__main__':n = 6source = 0weights = [[0, 1, 6], [0, 2, 4], [0, 3, 5], [1, 4, -1], [2, 1, -2], [2, 4, 3], [3, 2, -2], [3, 5, -1], [4, 5, 3]]print(bellmanFord(6, 0, weights))

4 A* 算法

作用

用来求两点之间的最短距离,虽然dijkstra算法也能算法图,但是如果图中节点的个数非常多,而且边也很多,dijkstra算法会找到所有的顶点,根据贪心算法进行排除,然找找到最短的距离。
A* 算法与dijkstra算法类似,可以理解为其是基于dijkstra算法优化而来的,不同的是A* 算法则会借助启发性搜索,避免一些无效节点的搜索。提高计算效率

思路:
对比dijkstra算法,为了因为启发性搜索,增加一个预估距离与最短距离加在一起,作为优先队列的key,每次将为

实现原理

假设有如下图结构,求节点A到节点F的最短距离,实现过程如下
在这里插入图片描述

  • 首先准备一个优先队列,一个最短距离前驱表t1,以及visisted存放是否已经i经访问过。t1[v] = (g, h ,v2)表示顶点A距离顶点v的最短距离g,顶点A距离顶点v的预估最短距离h,以及顶点v的前驱节点v1,其中(f = g + h)。初始的时候,顶点A到它自身的距离为0,其他顶点到顶点A的距离为无穷大,前驱节点为空,将(d + h,A)放到优先队列中(以第一位距离d+h 作为排序的key,小根堆)

  • 预估距离,起点到每个顶点都要提前设定一个预估距离,预估距离会作为优先队列的key的一部分,会影响实际遍历的顺序,预估距离一般由曼哈顿距离或者欧式距离给出,它不作为实际距离,只会影响搜索的方向。可以这样理解,如果能确认某些节点实际遍历的时候,大概率是不需要遍历的,则可以将该节点到起点的预估距离设定的大一些。

  • 首先从优先队列中取出首位距离最短的节点信息(18, A),然后依次遍历顶点A的所有边(B,D),将(15, B),(18,D)放到优先队列中,同时更新最短距离前驱表中的g项,并将顶点A放到visited表,表示下次遍历到顶点A的时候,直接忽略,具体结果如下:
    在这里插入图片描述

  • 然后再从优先队列中取出顶点(15, B)信息,依次遍历B所有的边(C,)其中A已经被放到visited中,无需再遍历,遍历B的边C的时候,发现权重之和(A->B + B->C =3 + 6 < 正无穷)小于当前表中已经存在的距离,故这里需要更新C的距离以及前驱,并将节点(9 + 7, C)放到优先队列中。

  • 后续的操作与上面一样,直到优先队列中的元素被取完在优先队列中提前碰到目标节点,如果从优先队列中取出的顶点到A的距离小于表中已经存在的距离或者已经处于visited表中,则直接忽略即可

  • 最后通过得到的最短距离前驱表可以得到顶点A到其他所有节点的最短距离以及对应的路径

  • 如果只需要求起点到某个终点的最短路径,则可以在优先队列中取到目标终点时,可以直接返回,无需再往下处理

def aStar(n, source, weights):## weights 列表的每一个元素格式为(n1, n2, w)表示顶点n1->n2的权重为w## n 表示顶点的格式,source表示原顶点## 这里需要将顶点信息都转化为0,1... n-1的编号# 为求顶点source 到其他顶点的最短距离neighbors = [[] for _ in range(n)]inf = float('inf')edges = [[inf for _ in range(n)] for _ in range(n)]for v1, v2, w in weights:neighbors[v1].append(v2)neighbors[v2].append(v1)edges[v1][v2] = wedges[v2][v1] = wpq = []g = {0: 18, 1: 12, 2: 7, 3: 11, 4: 5, 5: 0}visited = set()t1 = {}for i in range(n):t1[i] = (inf, g[i], -1)t1[source] = (0, g[source], -1)heapq.heappush(pq, (t1[0][0] + t1[0][0], source))while pq:f, v = heapq.heappop(pq)if f > (t1[v][0] + t1[v][1]) :continuevisited.add(v)for p in neighbors[v]:g1 = t1[v][0] + edges[v][p]if p not in visited and (g1 < t1[p][0]):t1[p] = (g1, t1[p][1], v)heapq.heappush(pq, (g1 + t1[p][1], p))return t1if __name__ == '__main__':n = 6source = 0weights = [[0, 1, 3], [0, 3, 7], [1, 2, 6], [2, 3, 8], [2, 4, 7], [2, 5, 10], [3, 4, 11], [4, 5, 7]]print(aStar(6, 0, weights))

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

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

相关文章

2025年8月新算法—云漂移优化算法(Cloud Drift Optimization Algorithm, CDO)

1、简介 这项研究介绍了云漂移优化&#xff08;数位长&#xff09;算法&#xff0c;这是一种创新的自然启发的元启发式方法来解决复杂的优化问题。CDO模仿受大气力影响的云粒子的动态行为&#xff0c;在探索和利用之间取得了微妙的平衡。它具有自适应权重调整机制&#xff0c;可…

VS Code进行.NET开发时使用断点和热重载

VS Code 调试热重载 1. VS Code 设置 安装扩展&#xff1a;C#、C# Dev Kit设置中搜索hot reload&#xff0c;选择C#开发工具包&#xff0c;把下图的几项全部打勾2. 启动项目&#xff08;仅用左侧“运行和调试”&#xff09; 打开解决方案&#xff0c;选你的启动项目的“.NET La…

mysqlbinlog解析命令

解析 MySQL Binlog 详细信息的命令以下是解析 MySQL Binlog 详细信息的常用命令&#xff1a;1. 基本 binlog 解析命令# 查看 binlog 文件内容&#xff08;基本格式&#xff09; mysqlbinlog /var/lib/mysql/mysql-bin.000001# 查看特定时间段的 binlog mysqlbinlog --start-dat…

算法训练营day60 图论⑩ Bellman_ford 队列优化算法、判断负权回路、单源有限最短路(修改后版本)

增加对最短路径的优化算法、负权回路、单源有限最短的讲解 Bellman_ford 队列优化算法 -------------------------------------------------------------------------------- 8.24更新&#xff1a;该算法是针对带负值的最短路径的优化算法&#xff0c;核心通过队列来实现&…

Python 学习(十六) 下一代 Python 包管理工具:UV

目录1. UV 介绍1.1 什么是UV&#xff1f;1.2 UV的核心优势1.3 UV和其他工具对比1&#xff09;UV vs. pipvirtualenv2&#xff09;UV vs. Conda3&#xff09;UV vs. Poetry4&#xff09;功能对比表2. UV的安装与常用命令2.1 安装UV1&#xff09;使用官方安装脚本&#xff08;推荐…

Redis学习笔记 ----- 缓存

一、什么是缓存 缓存&#xff08;Cache&#xff09;是数据交换的缓冲区&#xff0c;是存储数据的临时地方&#xff0c;一般读写性能较高。 &#xff08;一&#xff09;缓存的作用 降低后端负载&#xff1a;减少对数据库等后端存储的直接访问压力。提高读写效率&#xff0c;降低…

React响应式链路

文章目录响应式链路的核心环节1.状态定义与初始化2.状态更新触发&#xff08;状态变更&#xff09;3.调度更新&#xff08;Scheduler&#xff09;4.重新渲染&#xff08;Render 阶段&#xff09;5.协调&#xff08;Reconciliation&#xff09;与 Fiber 架构6.提交更新&#xff…

软件设计师——计算机网络学习笔记

一、计算机网络 网络基础 1. 计算机网络的分类2. 网络拓扑结构 总线型(利用率低、干扰大、价格低) 星型(交换机形成的局域网、中央单元负荷大) 环型(流动方向固定、效率低扩充难) 树型(总线型的扩充、分级结构) 分布式(任意节点连接、管理难成本高)一般来说&#xff0c;办公室局…

1200 SCL学习笔记

一. IF. 如果。下面是一个起保停IF #I_start AND NOT #I_stop THEN //如果I_start接通 和 I_stop没有接通#Q_run : 1; //输出Q_run 接通 ELSIF #I_stop THEN //如果I_stop接通#Q_run : 0; //。。。。。。 END_IF;二. CASECASE…

单例模式与线程池

1. 单例模式单例模式是一种常用的设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。这种模式在需要控制资源访问、管理共享状态或协调系统行为时非常有用。单例模式的核心特点&#xff1a;私有构造函数&#xff1a;防止外部通过n…

Chrome和Edge如何开启暗黑模式

Edge和Chrome浏览器都提供了实验性功能&#xff0c;可以通过修改实验性设置来开启暗黑模式。 在浏览器地址栏中输入edge://flags/&#xff08;Edge&#xff09;或chrome://flags/&#xff08;Chrome&#xff09;。在搜索框中输入“dark”&#xff0c;找到与暗黑模式相关的选项。…

【科研绘图系列】浮游植物的溶解性有机碳与初级生产力的关系

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍 数据准备 数据处理 溶解性有机碳(DOC)与初级生产力(NPP)的关系 溶解性有机碳(DOC)与光照强度(PAR)的关系 数据可视化 加载R包 数据下载 导入数据 画图1 画图2 总结 系统信…

IDEA相关的设置和技巧

IDEA相关的设置和技巧 我的博客对应文章地址 1.布局设置 IDEA的布局自定义程度很高&#xff0c;顶部工具栏&#xff0c;侧边栏都可以随意定制&#xff0c;设置好的布局方案可以保存&#xff0c;在新项目中快速使用 1.1 工具栏设置 [!tip] 举个例子&#xff1a;比如我要在顶部…

AWS Lambda 完全指南:解锁无服务器架构的强大力量

在云计算的发展浪潮中,无服务器(Serverless) 架构已然成为构建现代应用的新范式。而在这场变革的中心,AWS Lambda 作为开创性的 Function-as-a-Service (FaaS) 服务,彻底改变了我们部署和运行代码的方式。 本文将带您深入探索 AWS Lambda,从核心概念、工作原理到高级实践…

人工智能时代下普遍基本收入(UBI)试验的实践与探索——以美国硅谷试点为例

一、硅谷UBI试验的最新进展&#xff08;2025年&#xff09;1. 试验规模与资金来源圣克拉拉县试点&#xff1a;硅谷所在地圣克拉拉县针对脱离寄养家庭的年轻人开展UBI试验&#xff0c;每月发放1000美元补贴&#xff0c;持续1-2年&#xff0c;覆盖约60名参与者&#xff0c;成本约…

云计算之云主机Linux是什么?有何配置?如何选?

一、云环境如何选择Linux发行版 1.1、Linux在各个领域的发展 Linux在各个领域的发展序号Linux发展领域说明1Linux在服务器领域的发展目前Linux在服务器领域已经占据95%的市场份额&#xff0c;同时Linux在服务器市场的迅速崛起&#xff0c;已经引起全球IT产业的高度关注&#xf…

XCVU13P-2FHGB2104E Xilinx(AMD)Virtex UltraScale+ FPGA

XCVU13P-2FHGB2104E 是 Xilinx&#xff08;AMD&#xff09;Virtex UltraScale FPGA 系列中的一款高性能芯片&#xff0c;适用于需要大量逻辑资源、高带宽和高速数据传输的应用场景。作为该系列中的旗舰产品&#xff0c;XCVU13P-2FHGB2104I 结合了强大的处理能力和灵活的可编程性…

自动化单词例句获取系统设计方案

方案一 (网络爬虫) 这个方案的核心思路是:创建一个自动化的脚本,该脚本会读取你 MongoDB 中的单词,然后去一个免费的在线词典网站上抓取这些单词的例句,最后将抓取到的例句存回你的 MongoDB 数据库中对应的单词条目下。 一、 核心思路与技术选型 自动化脚本: 我们将使用 P…

WPF Alert弹框控件 - 完全使用指南

WPF Alert弹框控件 - 完全使用指南概述快速开始nuget安装与引用基本用法功能特性详细说明AlertType 枚举方法参数详解Show 方法&#xff08;局部弹窗&#xff09;ShowGlobal 方法&#xff08;全局弹窗&#xff09;完整示例代码XAML 布局C# 代码实现界面演示功能特性对比表格自定…

可视化-模块1-HTML-01

1-软件下载&#xff1a; 软件名称&#xff1a;HBuilderX 官网地址&#xff1a; https://www.dcloud.io/hbuilderx.html 下载文佳-解压缩-打开exe文件 创建快捷方式至桌面 2-创建项目 【普通项目】-【基本HTML项目】-【项目名&#xff1a;week1-1】 【index】输入&#xff1…