数据结构之图:加权有向图与dijkstra算法找到最短路径,Python——28

加权有向图与dijkstra算法找到最短路径

加权有向图的构造

最短路径问题与最短路径树

最短路径问题(The shortest path problem)定义

  • 最短路径可以是时间花费最短,也可以是距离最短,或是花费最少
  • 在图论中,最短路径问题指的是一个graph中,想要找到两个顶点之间的路径使它们间连通的全部边的权重和最小化

最短路径的性质

  1. 路径具有方向性
  2. 权重不一定等价于距离。权重可以是距离、时间、花费等内容,权重最小指的是成本最低
  3. 只考虑连通图。一副图中并不是所有的顶点都是可达的,如果s和t不可达,那么它们之间也就不存在最短路径,为了简化问题,这里只考虑连通图。
  4. 最短路径不一定是唯一的。 从一个顶点到达另外一个顶点的权重最小的路径可能会有很多条,这里只要找出一条即啊。

使用dijkstra算法找到最短路径树

最短路径树(Shortest-path tree)定义

  • 给定一副加权有向图和一个顶点s,以s为起点的一棵最短路径树是图的一副子图,它包含顶点s以及从s可达的所有顶点。这棵有向树的根结点为s,树的每条路径都是有向图中的一 条最短路径。
    去往dijkstra算法
class DirectedEdge:def __init__(self, _from, _to, weight):self._from = _fromself._to = _toself.weight = weightdef get_weight(self):return self.weightdef start(self):return self._fromdef end(self):return self._to
  • 加权有向图的边具有方向,其中_from是出发顶点;_to是目的顶点;weight是这条边的权重。

加权有向图的实现

去往dijkstra算法

from Structure.graph.DirectedEdge import DirectedEdgeclass WeightedDigraph:def __init__(self, num):self.num_vertices = numself.num_edges = 0self.adj_list = [[] for _ in range(num)]def add_edge(self, edge: DirectedEdge):_from = edge.start()# _to = edge.end()self.adj_list[_from].append(edge)self.num_edges += 1def get_all_edges_of(self, v):"""Get all edges connected with v"""return self.adj_list[v]def get_all_edges(self):"""Get all edges of this graph"""return [e for i in range(self.num_vertices) for e in self.adj_list[i]]
  • num_vertices 定义了图中顶点的个数;num_edges 为边的数量,初始状态下各顶点相互分隔,边数量为0;adj_list 是一个列表,索引代表顶点,每个值也是一个列表,储存着对应顶点通向的目的顶点;
  • add_edge(edge: DirectedEdge)传入一个DirectedEdge对象,向adj_list中对应位置添加一条有向边;
  • get_all_edges_of(v) 获取传入的顶点v的所有通往的边
  • get_all_edges() 获取整张图的所有的边;

松弛方法relax的过程

  • 当前已经存在一条最短路径S->W且知道其路径总权重SP_weight[w],现在要判断下一条路径S->V->W是否更短,则首先计算S->V的最短路径的总权重SP_weight[V],然后再加上V->W的最短边的权重,如果相加之和大于之前最短路径的权重和SP_weight[W],则无需松弛,无需更新数据
    在这里插入图片描述
  • 当从起点S到达V的最短路径的权重之和加上从V到达W的权重小于从起点S到达W的最短路径权重之和时,则对应松弛成功的情况,需要将从S到W的最短路径权重之和SP_weight[W]更新为SP_weight[V] + [V到W边的权重],到达终点前的最后一条边last_edge要更新为[V→W]在这里插入图片描述
  • 顶点的松弛是基于边的松弛完成的,只需要把某个顶点指出的所有边松弛,那么该顶点就松弛完毕。例如要松弛顶点v,只需要遍历v的邻接表,把每一边都松弛,那么顶点v就松弛了。

在这里插入图片描述

Python代码实现dijkstra算法寻找最短路径

from Structure.graph.DirectedEdge import DirectedEdge
from Structure.graph.WeightedDigraph import WeightedDigraph
from Structure.PriorityQueue.IndexMinPriorityQueue import IndexMinPriorityQueue
from math import infclass DijkstraSP:def __init__(self, graph, start_vertex=0):self.graph = graphself.start_vertex = start_vertex# Each vertex(index) point to a minimum weight from the start vertex(0)self.SP_weight = [inf for _ in range(self.graph.num_vertices)]# Store the last SPT edge from 0 to the vertex(index)self.last_edge = [None for _ in range(self.graph.num_vertices)]# Store all edges? of the SPT(all the last_edge)# Index equals to vertex, element equals to edge.weight from the current vertexself.SPT_edge_weights = IndexMinPriorityQueue(self.graph.num_vertices)  # num_vertices - 1 + 1self.SP_weight[start_vertex] = 0.0# Index equals to vertex, element equals to weightself.SPT_edge_weights.insert(start_vertex, 0.0)while self.SPT_edge_weights.size() > 0:min_weight_vertex = self.SPT_edge_weights.delete_min_and_get_index()# print(f"min_weight_vertex {min_weight_vertex}")self.relax(min_weight_vertex)def relax(self, v):"""Check if the total weight from 0 to v is lesser than from 0 to w"""# To relax a vertex is to relax all its edgesfor e in self.graph.get_all_edges_of(v):w = e.end()if self.SP_weight[v] + e.weight < self.SP_weight[w]:self.SP_weight[w] = self.SP_weight[v] + e.weightself.last_edge[w] = eif self.SPT_edge_weights.is_index_exist(w):self.SPT_edge_weights.change_item(w, e.weight)else:self.SPT_edge_weights.insert(w, e.weight)def sp_weight_to(self, v):"""Get the total weight of a shortest path from 0 to v"""return self.SP_weight[v]def has_path_to(self, v):"""Check if the start vertex to v is feasible"""# return self.graph.adj_list[v]return self.SP_weight[v] < infdef shortest_path_to(self, v):"""Get all the shortest path edges from 0 to v"""if not self.has_path_to(v):returnall_sp_edges = []while True:e = self.last_edge[v]if not e:breakall_sp_edges.insert(0, e)v = e.start()return all_sp_edges
属性和方法说明
  1. 构造方法__init__()中
    graph 接收传入的图对象;start_vertex 为要找出最短路径树的起始顶点;
    SP_weight是一个列表,索引代表当前顶点,值代表从起点出发到索引对应顶点的最短路径的权重和,它初始化储存全部为无穷大inf,可以使搜寻时路径时的初次权重比较一定会成功;
    last_edge是一个列表,索引对应着顶点,储存的值表示从起点到索引对应顶点的最短路径中的最后一条边;
    SPT_edge_weights是一个最小优先队列MinIndexPriorityQueue对象,索引代表顶点,存入的值是从起点到当前遍历顶点的经过松弛relax()后的路径上的最后一条边的权重,其实就是对应的last_edge的权重
  2. relax(v) 松弛图graph中的顶点v,下面会介绍其操作过程
  3. sp_weight_to(v) 获取从起点到传入的顶点v的SP的权重和
  4. has_path_to(v) 检查图中从起点出发,是否存在一条路径能到达顶点v
  5. shortest_path_to(v) 获取从起点到达顶点v的SP经过的的所有边

回到DirectedEdge
回到WeightedDigraph
其中用到的的索引最小优先队列IndexMinPriorityQueue传送门

运行测试:
if __name__ == '__main__':with open('../DSP.txt', 'r') as f:num_vertices = int(f.readline())num_edges = int(f.readline())graph = WeightedDigraph(num_vertices)edge = DirectedEdgefor _ in range(num_edges):_from, _to, weight = f.readline().split()# print(_from, _to, weight)graph.add_edge(edge(int(_from), int(_to), float(weight)))end = 6DSP = DijkstraSP(graph, 0)# print([e.start() for e in DSP.shortest_path_to(end)] + [end])print(DSP.sp_weight_to(end))print(DSP.has_path_to(end))for e in DSP.shortest_path_to(end):print(f"{e.start()}-->{e.end()}, {e.weight}")

运行结果:

1.5100000000000002
True
0-->2, 0.26
2-->7, 0.34
7-->3, 0.39
3-->6, 0.52

0 → 2 → 7 → 3 → 6

对比参考结果:
在这里插入图片描述

DSP.txt

8
15
4 5 0.35
5 4 0.35
4 7 0.37
5 7 0.28
7 5 0.28
5 1 0.32
0 4 0.38
0 2 0.26
7 3 0.39
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93

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

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

相关文章

李沐动手学深度学习pytorch :问题:找不到d2l包,No module named ‘d2l’

同学你好&#xff01;本文章于2021年末编写&#xff0c;已与实际存在较大的偏差&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)…

解决loaded more than 1 DLL from .libs和No metadata found in lib\site-packages两个错误

### 卸载numpy pip uninstall numpy 解决No metadata found in lib\site-packages 去这个文件夹下找到numpy的两个文件夹 删除 然后重新输入pip install numpy

ERROR 2002 (HY000): Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘

启动数据库时报错&#xff0c;代码ERROR 2002 (HY000) 报错截图&#xff1a; 原因&#xff1a;网络环境发生改变&#xff0c;mysql配置文件中绑定的IP与现在系统的IP不一致 解决&#xff1a;修改配置文件中绑定的IP地址为本系统的IP地址 使用命令&#xff1a; sudo vi /etc/…

图像目标分割_1 概述

6.1.1 什么是目标分割 定义&#xff1a;在计算机视觉领域&#xff0c;图像分割&#xff08;Object Segmentation&#xff09;指的是将数字图像细分为多个图像子区域&#xff08;像素的集合&#xff09;的过程。 图像分割的目的&#xff1a;简化或改变图像的表示形式&#xff0…

字符数组和strcpy

已知strcpy函数的原型是char *strcpy(char *strDest, const char *strSrc);&#xff0c;其中strDest是目的字符串&#xff0c;strSrc是源字符串。 &#xff08;1&#xff09;Write the function strcpy, dont call C/C string library.&#xff08;不调用C/C的字符串库函数&…

Django开发中问题和报错集合

记录django项目开发过程中的遇到的问题&#xff0c;导致原因和已经奏效的解决方法 常见报错UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xbc in position 852: invalid start byte 这个问题在一些电脑上做django开发时经常出现 要么是py文件运行是就报这个类似…

图像目标分割_2 FCN(Fully Convolutional Networks for Semantic Segmentation)

6.2.1 FCN 背景介绍 图像语义分割&#xff1a;给定一张图片&#xff0c;对图片上每一个像素点进行分类&#xff01;但是与图像分类目的不同&#xff0c;语义分割模型要具有像素级的密集预测能力才可以。 6.2.2 FCN介绍 6.2.2.1 全卷积网络 全卷积网络&#xff0c;模型由卷积…

求4个数字组成的不重复三位数,Python简洁解法

求4个数字组成的不重复三位数&#xff0c;Python解法 题目要求&#xff1a; 求所有由5,6,7,8组成的数字不重复的三位数 不重复的三位数&#xff0c;即不能出现555,566这种 通过分析&#xff0c;可以使用画树的方法来确定要求的三位数的值与个数 按照上图所示可以确定由5&am…

图像目标分割_3 SegNet + U-Net

6.3.1 SegNet背景 SegNet的主要动机是场景理解的应用。 难点&#xff1a;因此它在设计的时候考虑了要在预测期间保证内存和计算时间上的效率。分割的任务其实应用非常地广&#xff0c;需要理解各个像素之间的关系&#xff0c;比如要区分出人行道和车行道&#xff0c;建筑物和…

MIPI屏数据发送命令解析

MIPI数组发送那里有一个数组&#xff0c;这个数组包含寄存器和寄存器的值&#xff1a; 相当于: 0XC480寄存器下参数0X9C&#xff1b; 0XFF00寄存器下参数0XFF,0XFF,0XFF&#xff1b; 0XC0B5 尝试一下寄存器 0x08 0x18 0x48 0x58 试一下能不能旋转

面向对象之类的内建函数

类的特殊成员 上文介绍了Python的类成员以及成员修饰符&#xff0c;从而了解到类中有字段、方法和属性三大类成员&#xff0c;并且成员名前如果有两个下划线&#xff0c;则表示该成员是私有成员&#xff0c;私有成员只能由类内部调用。无论人或事物往往都有不按套路出牌的情况&…

图像目标分割_4 DeepLab-V1

6.4.1 DeepLab 背景 相比于传统的视觉算法(SIFT或HOG)&#xff0c;Deep-CNN以其end-to-end方式获得了很好的效果。这样的成功部分可以归功于Deep-CNN对图像转换的平移不变性(invariance)&#xff0c;这根本是源于重复的池化和下采样组合层。平移不变性增强了对数据分层抽象的能…

图像目标分割_5 DeepLab V2 V3 V3+

6.5.1 DeepLab V2 6.5.1.1 改变特点 atrous convolution采用ASPP ( atrous spatial pyramid pooling) 多尺度获得更好的分割效果合并深度卷积网络和概率图模型方法&#xff0c;增强对物体边界的定位。基础层由VGG16转为ResNet 和v1不同&#xff1a; 通过多尺度输入处理或者多…

Python导包、模块报错的问题

import报错No module named "xxx"的问题 如何将指定目录作为项目根目录&#xff0c;让项目根目录下的包/模块都可以直接导入&#xff1f;&#xff08;linux下&#xff09; Python导入模块时&#xff0c;解释器如何定位模块&#xff1a; 1.当前目录 2.内置模块列表 3…

CC2540 串口0 通道2配置

从图里面可以看出来&#xff0c;串口0有两个通道&#xff0c;一个通道是P02 P03两个GPIO口。 还有一个通道是P14 P15两个GPIO口。 在软件配置的时候&#xff0c;主要是配置的是一个通道相关的寄存器。 7.6.4 USART 0 The SFR register bit PERCFG.U0CFG selects whether to u…

图像目标分割_6 Mask RCNN

6.6.0 背景 目标检测和语义分割的效果在短时间内得到了很大的改善。在很大程度上&#xff0c;这些进步是由强大的基线系统驱动的&#xff0c;例如&#xff0c;分别用于目标检测和语义分割的Fast/Faster R-CNN和全卷积网络(FCN)框架。这些方法在概念上是直观的&#xff0c;提供…

SCI论文写作训练营笔记汇总01_概述+文献检索与管理

1 概述 1.1 适用人群 ①初涉科研&#xff0c; 目前或将来有英文科技论文发表需求的科研工作者 ②正在撰写或准备撰写英文科技论文的科研工作者 1.2 科技论文的基本结构 1.3 科技论文组成部分的写作方法 1.4 阅读文献的重要性 2、文献检索与管理 2.1 如何查找文献参考 2.2 文…

天猫11.11:搜索引擎实时秒级更新(转载)

搜索是很多用户在天猫购物时的第一入口&#xff0c;搜索结果会根据销量、库存、人气对商品进行排序&#xff0c;而商品的显示顺序往往会决定用户的选择&#xff0c;所以保证搜索结果的实时性和准确性非常重要。在电商系统中&#xff0c;特别是在“双十一”这样的高并发场景下&a…

OAD 空中升级

http://www.deyisupport.com/question_answer/wireless_connectivity/bluetooth/f/103/p/69222/172351.aspx#172351&#xfeff;&#xfeff;第二十三节 OAD空中升级 通过仿真器更新程序或者通过USB更新固件那都是一般人都可以实现的操作&#xff0c;但是要想实现OAD空中升级…

SCI论文写作训练营笔记汇总02_英文科技论文阅读与解析

3、英文科技论文阅读与解析的方法 3.1 科技论文介绍 3.1.1 科技论文的类型 • Research • Review • Theoretical • Methodological • Case study 3.1.2 研究型论文的结构 3.1.3 科技论文的基本结构 3.2 文献阅读 3.2.1 文献选择的原则 3.2.2 文献阅读顺序 3.2.2 文献阅读…