有向无权图的最短路径

在运筹学领域的经典模型中,最大流问题、多商品网络流问题和最短路径问题等都依附在图上对问题进行描述,同样,当我们梳理问题的数学模型,或理解相关问题的求解算法时,也要依靠它。因此,我将总结和图相关的问题,并梳理各类问题的求解算法。本文先对寻找有向无权图最短路径的方法进行小结。

文章目录

    • 图的定义和种类
    • 寻找有向无权图最短路径
    • 算法实现

图的定义和种类

在这里插入图片描述

如上所示,在一个图中有两个重要的组成元素,分别是节点和边,通常我们会把节点集合记作 V = { v 1 , v 2 . . . v n } V=\lbrace v_1,v_2...v_n \rbrace V={v1,v2...vn},将边记作 E = { e 1 , e 2 , . . . e m } E=\lbrace e_1,e_2,...e_m \rbrace E={e1,e2,...em},这样就可以用数学方式表示出来一个图 G = ( V , E ) G=(V,E) G=(V,E)。图中的节点可以表示实际生活中的对象,节点之间的边可以理解为对象之间的特定关系;比如,可以将上图中每个节点想象为每个城市的火车站,那边就可以看作两座城市的火车站之间可以通车。

有了图的基本概念后,伴随着各种各样的问题,就有了形形色色的图。假设还把它理解为城市之间的火车站连通情况,现在我想在这副图上表示出两个城市之间火车通车的时间,那我就可以给每条边加上权重,这样它就变成了无向有权图;如果车站之间是单程的(只是假定),那我就可以给每条边加上方向,这样就得到一个有向有权图 。下图是一个有向有权图。

在这里插入图片描述

寻找有向无权图最短路径

在有向无权图中,我们将相邻节点之间的路径长度定义为 1 1 1。寻找有向无权图的最短路径,即给定一个起点和终点后,找到一个从起点到终点距离最短的路径; 也可以理解为从起点经过最少数量的节点,到达终点(仅限有向无权图)。

在这里插入图片描述

求解有向无权图的最短路径算法中, 给算法输入一个图和起点,就可以得到从起点到各点的最短路径。接下来以上图为例,讲述算法的求解过程。

初始化阶段,准备一个Queue,并初始化一个Status table,如下表所示。
在这里插入图片描述

Status table中,有四列,第一列是图中的节点名称,第二列表示该节点有没有被访问过,初始时所有节点设置为 n o no no,第三列 d i s t dist dist表示该节点与起点之间的距离,初始时设置为 i n f inf inf,即为无限远;第四列为该节点在最优路径中对应的前置节点,初始时设置为 0 0 0

  • 初始化

我们假设起点为 v 3 v_3 v3,寻找到剩余节点的最短路径。在初始化阶段,将Status table中的起点 v 3 v_3 v3 v i s i t visit visit设置为 y e s yes yes,自己和自己的距离为 0 0 0,设置 d i s t dist dist为0。同时,将起点 v 3 v_3 v3放入Queue中。这些完成后,我们可以进行第一轮循环。

在这里插入图片描述

  • Iteration 1
    • 从队列中取出第一个节点,即 v 3 v_3 v3
    • 根据给出的图发现,节点 v 3 v_3 v3的相邻节点有 v 1 v_1 v1 v 6 v_6 v6
      • 更新 v 1 v_1 v1 v 6 v_6 v6 v i s i t visit visit y e s yes yes,代表已经被访问过。更新 d i s t dist dist为1( v 3 v_3 v3 v 1 v_1 v1的距离为1)。更新 p a t h path path v 3 v_3 v3
      • v 1 v_1 v1 v 6 v_6 v6放入Queue队列中。
    • 进行第二轮循环

在这里插入图片描述

  • Iteration 2

    • 从队列中取出第一个节点,即 v 1 v_1 v1

    • 根据给出的图发现,节点 v 1 v_1 v1的相邻节点有 v 2 v_2 v2 v 4 v_4 v4

      • 更新 v 2 v_2 v2 v 4 v_4 v4 v i s i t visit visit y e s yes yes,代表已经被访问过。更新 d i s t dist dist1+1( v 3 v_3 v3 v 1 v_1 v1的距离为1, v 1 v_1 v1 v 2 v_2 v2的距离为1,因此为2)。更新 p a t h path path v 1 v_1 v1
      • v 2 v_2 v2 v 4 v_4 v4放入Queue队列中。
    • 进行第三轮循环

在这里插入图片描述

  • Iteration 3

    • 从队列中取出第一个节点,即 v 6 v_6 v6

    • 根据给出的图发现,节点 v 6 v_6 v6没有相邻节点。不做操作。

    • 进行第四轮循环

在这里插入图片描述

  • Iteration 4

    • 从队列中取出第一个节点,即 v 2 v_2 v2

    • 根据给出的图发现,节点 v 2 v_2 v2的相邻节点有 v 4 v_4 v4 v 5 v_5 v5

      • 由于 v 4 v_4 v4已经被访问过了,不需要更新
      • 更新 v 5 v_5 v5 v i s i t visit visit y e s yes yes,代表已经被访问过。更新 d i s t dist dist2+1。更新 p a t h path path v 2 v_2 v2
      • v 5 v_5 v5放入Queue队列中。
    • 进行五轮循环

在这里插入图片描述

  • Iteration 5

    • 从队列中取出第一个节点,即 v 4 v_4 v4

    • 根据给出的图发现,节点 v 4 v_4 v4的相邻节点有 v 3 v_3 v3 v 5 v_5 v5 v 6 v_6 v6 v 7 v_7 v7

      • 由于 v 3 v_3 v3 v 5 v_5 v5 v 6 v_6 v6已经被访问过了,不需要更新
      • 更新 v 7 v_7 v7 v i s i t visit visit y e s yes yes,代表已经被访问过。更新 d i s t dist dist2+1。更新 p a t h path path v 4 v_4 v4
      • v 7 v_7 v7放入Queue队列中。
    • 判断Queue是否为空,若不为空,进行第六轮循环,若为空,则结束,Status table中记录了起点到其他所有节点的最短距离和路径。

在这里插入图片描述

  • Iteration 6

    • 从队列中取出第一个节点,即 v 5 v_5 v5

    • 根据给出的图发现,节点 v 5 v_5 v5的相邻节点有 v 7 v_7 v7

      • 由于 v 7 v_7 v7已经被访问过了,不需要更新
    • 判断Queue是否为空,若不为空,进行第七轮循环,若为空,则结束,Status table中记录了起点到其他所有节点的最短距离和路径。

在这里插入图片描述

  • Iteration 7

    • 从队列中取出第一个节点,即 v 7 v_7 v7

    • 根据给出的图发现,节点 v 7 v_7 v7的相邻节点有 v 6 v_6 v6

      • 由于 v 6 v_6 v6已经被访问过了,不需要更新
    • 判断Queue是否为空,若不为空,进行第八轮循环,若为空,则结束,Status table中记录了起点到其他所有节点的最短距离和路径。已经为空,结束。

在这里插入图片描述

通过上面的手算,我们理清了寻找有向无权图最短路径的算法步骤,有几个需要注意的地方用加粗标识出来。

算法实现

沿着上面的求解思路,我们不难得出,算法的结束标志就是队列是否为空,若为空,则代表算法结束。下面是我用python求解的代码,给一个图、起点和终点,得到最优路径。

import networkx as nx
import matplotlib.pyplot as plt
import math#-------------------------------构建有向无权图-----------------------------------
# 创建无权有向图
Graph = nx.DiGraph()
# 添加节点
Graph.add_nodes_from(['v1', 'v2', 'v3', 'v4', 'v5', 'v6', 'v7'])
# 添加边
Graph.add_edges_from([('v1', 'v2'),('v1', 'v4'),('v2', 'v4'),('v2', 'v5'),('v3', 'v1'),('v3', 'v6'),('v4', 'v3'),('v4', 'v5'),('v4', 'v6'),('v4', 'v7'),('v5', 'v7'),('v7', 'v6'),
])
# 获取节点和边的数量
# print(list(Graph.edges))
# print(list(Graph.nodes))
# 画图
# nx.draw(Graph, pos=nx.planar_layout(Graph), with_labels=True)
# plt.show()#-------------------------------寻找最短路径-----------------------------------
def find_shortest_path(Graph, begin_node, end_node):# 1. 初始化列表,用来存放节点select_nodes        = []neighboring_nodes   = []# 2. 初始化键值为列表的字典,存放访问信息total_nodes_status  = {}for node in Graph.nodes:total_nodes_status[node] = ['false', None, ' ']#print(total_nodes_status[node])# 3. 将起点插入selct_nodesselect_nodes.append(begin_node)# 4. 更新total_nodes_status中的begin_nodetotal_nodes_status[begin_node][0] = 'true'total_nodes_status[begin_node][1] = 0#print(total_nodes_status)# 5. 当select_nodes不为空时执行如下循环操作while(len(select_nodes)!=0):# 5.1 取出队列顶端的节点current_node = select_nodes[0]select_nodes.remove(current_node)# 5.2 找到current_node相邻的节点, 若该节点没有被访问过, 将其放入neighboring_nodesneighboring_nodes.clear()for node in Graph.neighbors(current_node):if total_nodes_status[node][0] == 'false':neighboring_nodes.append(node)# 5.3 对于neighboring_nodes中的所有节点,做下面操作for node in neighboring_nodes:# 5.3.1 将node插入select_nodesselect_nodes.append(node)# 5.3.2 更新total_nodes_status中node被访问过total_nodes_status[node][0] = 'true'# 5.3.3 更新total_nodes_status中node的距离total_nodes_status[node][1] = total_nodes_status[current_node][1] + 1# 5.3.4 设置total_nodes_status中node的前置节点total_nodes_status[node][2] = current_node# 6. 若为空, 则执行完毕, 输出最终的状态for key, value in total_nodes_status.items():print(key, value)# 7.记录起点到终点的最优路径shortest_path = []shortest_path_length = total_nodes_status[end_node][1]current_node = end_nodewhile current_node != begin_node:shortest_path.append(current_node)current_node            = total_nodes_status[current_node][2]shortest_path.append(begin_node)shortest_path.reverse()return shortest_path_length, shortest_path#-------------------------------算例测试-----------------------------------
begin_node 	= 'v3'
end_node 	= 'v7'
shortest_path_length, shortest_path = find_shortest_path(Graph, begin_node, end_node)
print("起点%s到终点%s的最短距离是:%g \n ""路线如下所示:" % (begin_node, end_node, shortest_path_length))
path = ""
for element in shortest_path:if(element != end_node):path    += elementpath    += " -> "else:path    += elementprint(path)

当我输入起点 v 3 v_3 v3和终点 v 7 v_7 v7时,运行算法,最终的Status table和最优路径如图所示:
在这里插入图片描述

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

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

相关文章

Mac笔记本打开Outlook提示:您需要最新的版本的Outlook才能使用此数据库

Mac笔记本打开Outlook提示:您需要最新的版本的Outlook才能使用此数据库 故障现象: 卸载旧的office安装新版的office,打开outlook提示:您需要最新的版本的outlook才能使用此数据库。 故障截图: 故障原因:…

让文字在盒子中水平居中与垂直居中

简单方法&#xff1a; 1.先用text-align: center;将文字垂直居中。 2.再用line-height: Xpx;将元素的行高设置为与父元素同样的高度。&#xff08;这里的X代表父元素的高度&#xff09; 举例&#xff1a; 对于该网页的代码如下&#xff1a; <!DOCTYPE html> <html&…

AI中文版怎么用,版本分享,GPT官网入口

网页版上线啦&#xff0c;在线助力大学生、上班族的高效生活&#xff01; GPT4.0是OpenAI最新推出的聊天模型&#xff0c;它的语言理解和生成能力比以前的版本更强大。对于忙碌的上班族来说&#xff0c;GPT4.0能帮助你高效处理工作中的大部分写作任务&#xff0c;比如撰写报告…

Docker与VM虚拟机的区别以及Docker的特点

01、本质上的区别 VM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库&#xff0c;然后再安装应用&#xff1b; Container(Docker容器)&#xff0c;在宿主机器、宿主机器操作系统上创建Docker引擎&#xff0c;在引擎的基础上再安装应…

【MySQL】索引和事务(B树、B+树图解原理)

一、索引 1.1 什么是索引&#xff1f; 索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结构实现。 1.2 索引的作用 &#x1f693;&#xff08;1&#…

Android修行手册 - 阴影效果的几种实现以及一些特别注意点

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列点击跳转>ChatGPT和AIGC &#x1f449;关于作者 专…

m1 rvm install 3.0.0 Error running ‘__rvm_make -j8‘

在使用M1 在安装cocopods 前时&#xff0c;安装 rvm install 3.0.0遇到 rvm install 3.0.0 Error running __rvm_make -j8 备注: 该图片是借用其他博客图片&#xff0c;因为我的环境解决完没有保留之前错误信息。 解决方法如下&#xff1a; 1. brew uninstall --ignore-depe…

TCP协议通讯流程

文章目录&#xff1a; 通讯流程全过程浏览建立连接过程数据传输过程断开连接问题 通讯流程全过程浏览 下图是基于TCP协议的客户端/服务器程序的一般流程&#xff1a; 上图就是TCP协议的通信流程&#xff0c;接下来认识初步认识以下TCP建立连接&#xff08;三次握手&#xff0…

Notion汉化

Notion真无语&#xff0c;汉化版都没有。真的无力吐槽。 2023.11.7汉化经历 教程链接&#xff1a;github Reamd7/notion-zh_CN at 2.4.20-handmade (github.com) 网页版&#xff1a; 油猴下载插件。 Notion中文汉化 浏览器插件下载 windows&#xff1a; github realse 这…

【带头学C++】----- 六、结构体 ---- 6.7 共用体以及枚举类型

6.7 共用体以及枚举类型 结构体:结构体用于组合不同类型的数据&#xff0c;每个字段占用独立的内存空间。 共用体:共用体也组合不同类型的数据&#xff0c;但所有字段共享同一块内存。 因此&#xff0c;结构体适合表示具有多个属性的对象&#xff0c;而共用体适合表示可以具…

拜耳阵列(Bayer Pattern)以及常见彩色滤波矩阵(CFA)

一、拜耳阵列的来源 图像传感器将光线转化成电流&#xff0c;光线越亮&#xff0c;电流的数值就越大&#xff1b;光线越暗&#xff0c;电流的数值就越小。图像传感器只能感受光的强弱&#xff0c;无法感受光的波长。由于光的颜色由波长决定&#xff0c;所以图像传播器无法记录…

【JUC】八、阻塞队列

文章目录 1、阻塞队列概述2、阻塞队列分类3、 阻塞队列的四组核心方法4、Demo 队列&#xff0c;先进先出&#xff0c;类似排队栈&#xff0c;先进后出&#xff0c;用于要优先处理最近发生的事件的场景 1、阻塞队列概述 阻塞队列&#xff0c;一个生产消费模式&#xff0c;当&a…

【机器学习8】采样

1 均匀分布随机数 均匀分布是指整个样本空间中的每一个样本点对应的概率&#xff08;密度&#xff09; 都是相等的。 根据样本空间是否连续&#xff0c; 又分为离散均匀分布和连续均匀分布。编程实现均匀分布随机数生成器一般可采用线性同余法&#xff08;Linear Congruential…

防爆五参数气象仪的科技力量

WX-FBQ2 随着科技的不断进步&#xff0c;气象监测设备也在不断升级和完善。 防爆五参数气象仪是一种可以同时监测温度、湿度、压力、风速和风向五个基本气象参数的仪器。它采用了气象监测技术&#xff0c;不仅可以实时监测气象数据&#xff0c;还可以对数据进行分析和处理。 …

所见即所得的动画效果:Animate.css

我们可以在集成Animate.css来改善界面的用户体验&#xff0c;省掉大量手写css动画的时间。 官网&#xff1a;Animate.css 使用 1、安装依赖 npm install animate.css --save2、引入依赖 import animate.css;3、在项目中使用 在class类名上animate__animated是必须的&#x…

轻松预览:Axure RP在线原型展示指南,快速掌握!

当UI设计师想要提供功能和细节丰富的原型时&#xff0c;可以使用原型设计工具预览Axure原型。原型设计工具Axurerp作为线框图和原型制作工具的创始人&#xff0c;功能非常强大。取代Axure的国产原型设计工具即时设计&#xff0c;界面布局清新&#xff0c;非常适合复杂的原型设计…

黑马程序员微服务 第五天课程 分布式搜索引擎2

分布式搜索引擎02 在昨天的学习中&#xff0c;我们已经导入了大量数据到elasticsearch中&#xff0c;实现了elasticsearch的数据存储功能。但elasticsearch最擅长的还是搜索和数据分析。 所以今天&#xff0c;我们研究下elasticsearch的数据搜索功能。我们会分别使用DSL和Res…

【KCC@南京】KCC南京数字经济-开源行

一场数字经济与开源的视听盛宴&#xff0c;即将于11月26日&#xff0c;在南京举办。本次参与活动的有&#xff1a; 庄表伟&#xff08;开源社理事执行长、天工开物开源基金会执行副秘书长&#xff09;、林旅强Richard&#xff08;开源社联合创始人、前华为开源专家&#xff09;…

如何构建风险矩阵?3大注意事项

风险矩阵法&#xff08;RMA&#xff09;是确定威胁优先级别的最有效工具之一&#xff0c;可以帮助项目团队识别和评估项目中的风险&#xff0c;帮助项目团队对风险进行排序&#xff0c;清晰地展示风险的可能性和严重性&#xff0c;为项目团队制定风险管理策略提供依据。 如果没…

Word或者WPS批量调整文中图片大小的快捷方法

文章目录 0、前言1、编写宏代码2、在文档中调用宏实现一键批量调整3、就这么简单&#xff01; 0、前言 不知道大家是不是也和我一样&#xff0c;经常需要在编写的Word&#xff08;或者WPS&#xff09;文档里插入大量的图片&#xff0c;但是这些图片的尺寸大小一般都不一样&…