有向无权图的最短路径

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

文章目录

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

图的定义和种类

在这里插入图片描述

如上所示,在一个图中有两个重要的组成元素,分别是节点和边,通常我们会把节点集合记作 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.rhkb.cn/news/194026.html

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

相关文章

在Sprinng Boot中使用Redis充当缓存

关于我们使用EhCache可以适应很多的应用场景了,但是因为EhCache是进程内的缓存框架,在集群模式下,我们在我们的应用服务器或者云服务器之间的缓存都是独立的。故而在不同的服务器之间的进程会存在缓存不一致的情况,就算我们的EhCa…

flink 8081 web页面无法被局域网内其他机器访问

实现 http://localhost:8081/#/overview 可以被局域网其他机器访问

使用UART烧录N76E003AT20核心板

目录 模块简介烧录方式利用ISP对N76E003AT20核心板进行烧录ICP烧录BootloaderISP烧录程序(UART)测试现象 总结 模块简介 N76E003为带有flash的增强型8位8051内核微控制器(1T工作模式),指令集与标准的80C51完全兼容并具…

ROS stm32 CAN通信

文章目录 运行环境:原理1.1 ros中的代码1)socketcan_bridge2)测试的ros-python包3)keil5中数据解析4)USB-CAN连接5)启动指令 运行环境: ubuntu18.04.melodic STM32:DJI Robomaster C板 ROS:18.04 硬件:USB-CAN&#x…

基于 Amazon EKS 搭建开源向量数据库 Milvus

一、前言 生成式 AI(Generative AI)的火爆引发了广泛的关注,也彻底点燃了向量数据库(Vector Database)市场,众多的向量数据库产品开始真正出圈,走进大众的视野。 根据 IDC 的预测,…

入门后端开发得学什么?这份超详细的后端开发学习路线图值得推荐!

后端开发, 无疑是一个极为关键的领域,涉及到我们每日互联网生活的每个细节。每当你在网上浏览、搜索或进行购物等活动时,背后都有大量的后端技术作为支撑。而随着技术的日益进步,人们对于高效、稳定和安全的网络服务的需求也越来越高。 另一…

Docker-minio部署

1.创建目录 创建文件目录,用来存放配置和上传文件目录 (1)Minio 外部挂载的配置文件(/mydata/minio/config) (2)存储上传文件的目录(/mydata/minio/data) mkdir -p /home/minio/config mkdir -p /home/minio/data2.拉…

解决计算机丢失msvcr71.dll问题,总结5种解决方法分享

由于各种原因,计算机在使用的过程中可能会出现一些问题,其中之一就是丢失msvcr71.dll文件。这个问题可能会导致计算机无法正常运行某些程序或功能,给我们的生活和工作带来困扰。那么,当我们遇到这个问题时,应该如何解决…

微星迫击炮b660m使用intel arc a750/770显卡功耗优化方法

bios 优化: 1,开机后持续点击“delete”键直到进入微星bios。 2,点击右上角选择我们熟悉的中文。 3,点击Settings--->高级---> pcie/Pci子系统设置 4,Native PCIE Enable : Enabled Native Aspm:允许

2—10岁女童羽绒服,黑色长款也太好看了吧

冬天怎么能没有一件暖呼呼的羽绒服呢? 黑色长款羽绒服也赞了吧 大长款连帽,防风保暖设计 时尚与美观度都兼具呢!好穿又耐穿!

【EI会议征稿】第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024)

第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) The 3rd International Academic Conference on Blockchain, Information Technology and Smart Finance 第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) 将于2024年2月23-25日在马来西亚举行。本次会…

【计算机网络笔记】DHCP协议

系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…

关于400G光模块的常见问题解答

最近在后台收到了很多用户咨询关于400G光模块的信息,那400G光模块作为当下主流的光模块类型,有哪些问题是备受关注的呢?下面来看看小易的详细解答! 1、什么是400G QSFP-DD光模块? 答:400G光模块是指传输速…

三、Eureka注册中心

目录 一、作用及调用方式 二、搭建eureka注册中心 三、注册user-service和order-service 四、新增实例 五、服务拉取 六、总结 一、作用及调用方式 在服务提供者启动时,它会向eureka注册中心提供自己的信息,并每30秒进行一次刷新eureka注册中心保存…

bat随手记

目录 bat批处理常用命令查询有哪些reg命令,帮助信息——reg /?查询注册表信息——reg query /?切换到批处理文件目录——cd /d "%~dp0"永久设置环境变量——setx命令设置注册表内容——/v名称,/t类型,/d数据%cd%和%~dp0的区别/f没…

数据库测试的认知和分类详解

现在的软件系统,尤其是业务应用系统,后台都连接着一个数据库。数据库中存储了大量的数据,数据库的设计是否合理和完善,SQL语句编写是否正确、高效,都直接影响了一个软件系统的功能正确性和性能表现。今天跟大家分享一些…

metinfo 6.0.0 任意文件读取漏洞复现

metinfo 6.0.0 任意文件读取漏洞复现 漏洞环境 环境为mrtinfo 6.0.0 漏洞存在的位置 通过代码审计发现在源代码的/app/system/include/module/old_thumb.class.php这个位置有着任意读取文件漏洞 漏洞点:http://127.0.0.1/metinfo_6.0.0//include/thumb.php 漏洞复现 访…

efcore反向共工程,单元测试

1.安装efcore需要的nuget <PackageReference Include"Microsoft.EntityFrameworkCore" Version"6.0.24" /> <PackageReference Include"Microsoft.EntityFrameworkCore.SqlServer" Version"6.0.24" /> <PackageRefere…

Docker-compose 下载安装测试完成

源文件-http://t.csdnimg.cn/7NxHchttp://t.csdnimg.cn/7NxHc 1 docker-compose说明 Docker Compose 是Docker的组装工具&#xff0c;用于创建和调试多个Docker容器&#xff0c;并在同一个Docker主机上运行它们。Docker Compose基于YAML文件&#xff0c;描述多个容器之间的相…

香港科技大学广州|机器人与自主系统学域博士招生宣讲会—电子科技大学专场!!!(暨全额奖学金政策)

在机器人和自主系统领域实现全球卓越—机器人与自主系统学域 硬核科研实验室&#xff0c;浓厚创新产学研氛围&#xff01; 教授亲临现场&#xff0c;面对面答疑解惑助攻申请&#xff01; 一经录取&#xff0c;享全额奖学金1.5万/月&#xff01; &#x1f559;时间&#xff1a;…