[高阶数据结构六]最短路径算法

1.前言

最短路径算法是在图论的基础上讲解的,如果你还不知道图论的相关知识的话,可以阅读下面几篇文章。

[高阶数据结构四] 初始图论_初始图结构-CSDN博客

[高阶数据结构五] 图的遍历和最小生成树_图的遍历和生成树求解-CSDN博客

本章重点:

本章主要讲解图论的三种算法---DijkstraBallman-Ford,Floyd-Warshall算法。

2.单源最短路径

所谓的单源最短路径,也就是从图中任意一点出发, 到图中每个节点的最短路径,也就是最小的权值和。

举个例子:

为了要统计源点Srci即s到yztx四点的最短路径,通常使用两个数组来解决。

其中一个表示的是,从源点到当前点的最短路径的权值

另外一个表示的是,从源点到当前点最短路径的路径是什么。

//存储任意点到图中其他点的最短路径的权值vector<W>& dist//记录srci->其他顶点最短路径父顶点数组vector<int>& parentPath

这么说可能有点抽象,看如下图。

数组下标x处,对应的是t所在位置的下标,而t处对应的下标所在的位置是y。

dist中dist[4]表示从源点到x的最短路径为9。

3.Dijkstra算法

针对一个带权有向图 G ,将所有结点分为两组 S Q S 是已经确定最短路径的结点集合,在初始时 为空(初始时就可以将源节点s 放入,毕竟源节点到自己的代价是 0 ), Q 为其余未确定最短路径 的结点集合,每次从 Q 中找出一个起点到该结点代价最小的结点 u ,将 u Q 中移出,并放入 S 中,对 u 的每一个相邻结点 v 进行松弛操作

什么是松弛操作呢?

松弛即对每一个相邻结点 v ,判断源节点 s 到结点 u 的代价与u v 的代价之和是否比原来 s v 的代价更小,若代价比原来小则要将 s v 的代价更新 为s u u v 的代价之和,否则维持原样。

这样说有点抽象--但是如果你阅读了前面两篇文章,你会发现这个算法和Prim算法是有点类似的。

举例如下:

a处唯一确定的节点就是s,其余均是不确定的。在这里面找出一个与A直接相连,且路径是最短的出来,然后这个值那么一定是可以唯一确定的。

b处也用a处的方法,然后可以确定的节点是s,y,其余均为不确定的。

依次重复,有几个结点那么重复几次,一定可以把所有的节点确定下来。(这里的前提是权值均为正,不可以有负的)。后续解释为什么。

代码如下:

void Dijkstra(const V& src, vector<W>& dist, vector<int>& parentPath){//dist[i]表示srci到i位置的最短路径的权值//parentPath[i]表示推导出当前节点的下标.//即srci->B位置的最小权值是由srci->A->B推导而来,所以存储的是A的下标size_t n = _ver.size();dist.resize(n, int_MAX);parentPath.resize(n, -1);//-1表示初始时,没有路径能走到int srci = GetIndex(src);dist[srci] = 0;dist[srci] = W();parentPath[srci] = srci;vector<bool> visited(n, false);//n个节点,一共会更新n次,也可以判断visited数组中的元素是否全为truefor (int s = 0; s < n; s++){//每次找出dist中没有遍历过的,当前的最小的权值来做确定的顶点及边int u = 0;//表示顶点int min = int_MAX;//表示srci->u的权值for (int i = 0; i < n; i++){if (visited[i] == false && dist[i] < min){u = i;min = dist[i];}}//到这里就找到了最小的visited[u] = true;//开始进行松弛操作,即从srci->u->v的权值是否比srci->v的权值小,小的话就在dist中换掉for (int v = 0; v < n; v++){//这里松弛操作还有一个关键点,就是已经选定了的,即在visited里面是true的,后续哪怕找到了//比当前小的路径,也不在进行松弛操作了。理论上是不可能的,含有负权值除外if (visited[v]==false&&_martix[u][v] != int_MAX && dist[v] > dist[u] + _martix[u][v]){dist[v] = dist[u] + _martix[u][v];parentPath[v] = u;//表示u这个顶点->v顶点}}}}

这个算法是不支持有负权值的,这是因为一旦有了负权值,你之前唯一确定的点,可能就不是最短路径的值了。因为这里出现了环,那么可能出现的问题是:一直在环里面兜圈子,那么就会出现无穷小的情况。

例如:

4.BellMan-Ford算法

这个算法能够解决带有负权值的问题。

他是通过暴力的解法来搞定这个问题的。 它的时间复杂度是O(N^3). 它的思路就是以所有顶点为起始点,更新所有相连的边。

代码如下:

bool BellmanFord(const V& src, vector<W>& dist,vector<int>& parentPath){size_t n = _ver.size();dist.resize(n, int_MAX);parentPath.resize(n, -1);//-1表示暂时所有的都没有通路int srci = GetIndex(src);dist[srci] = W();for (int k = 0; k < n-1; k++){//加这个条件是有时候可能走3轮就不会再走后面的循环了,为了节省时间bool exchange = false;//开始暴力遍历n-1条边,并且更新权值cout << "第[" << k << "轮]" << endl;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){//srci ->i + i-> j 与srci->j的比较if (_martix[i][j] != int_MAX && dist[i] + _martix[i][j] < dist[j]){cout << "[" << _ver[i] << "]" << "->" << _ver[j] << ":" \<< _martix[i][j] << endl;dist[j] = dist[i] + _martix[i][j];parentPath[j] = i;exchange = true;}}}//到这里第一遍n-1条边的权值已经更新完了,但是有可能导致的因数是前面确定的边的值可能不是最小值,//前面确定边的值必须由后面确定边的值推导而来。一次暴力遍历n-1条边,可以至少确定一个顶点,有n个//顶点,所以至少要遍历n-1遍if (exchange == false) break;}//这里判断负权值的回路是否构成了环for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){//srci ->i + i-> j 与srci->j的比较if (_martix[i][j] != int_MAX && dist[i] + _martix[i][j] < dist[j]){return false;}}}return true;}

5.多源最短路径问题

简单的来说多源最短路径问题就是任意两点间的最短路径的权值以及走过的节点是什么。

那么这就需要两个二维数组来表示上述两个情况了。

 一个二维数组存储顶点i->j的最短路径的权值和, 另外一个数组存储 (i,j)的父节点下标. i,j是最短路径的节点。

6.Folyd-WarShall算法

Floyd算法考虑的是一条最短路径的中间节点,即简单路径p={v1,v2,…,vn}上除v1和vn的任意节
点。设k是p的一个中间节点,那么从i到j的最短路径p就被分成i到k和k到j的两段最短路径p1,p2。p1是从i到k且中间节点属于{1,2,…,k-1}取得的一条最短路径。p2是从k到j且中间节点属于{1,2,…,k-1}取得的一条最短路径

举个例子:

代码如下:

void FloydWarShall(vector<vector<W>>& vvDist, vector<vector<int>>& vvParentPath){//任意两点的最短路径//1.初始化size_t n = _ver.size();vvDist.resize(n);vvParentPath.resize(n);for (int i = 0; i < n; i++){vvDist[i].resize(n, int_MAX);vvParentPath[i].resize(n, -1);}//先初始化那些直接相连的for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){if (i == j){vvDist[i][j] = 0;vvParentPath[i][j] = -1;}if (_martix[i][j] != int_MAX){vvDist[i][j] = _martix[i][j];vvParentPath[i][j] = i;}}}//任意两点间的最短路径---abcdef  求a->f之间的最短路径,假设中间点为k,//可能经过k点,也可能不经过k点//若经过k点,dist[i][j]=dist[i][k]+dist[k][j]//不经过k点的话,那么dist[i][j]=dist[i][j],此时i-j之间是少了k点这个值的//那么问题就转换成找k点了,那么k点是谁呢? a->f k点可能是b c d e//若求的是b->e最短路径呢? 那么k点可能是a c e f。//通过上述分析发现,任意一个点都有可能成为k点。for (int k = 0; k < n; k++){for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){if (vvDist[i][k] != int_MAX && vvDist[k][j] != int_MAX&& vvDist[i][k] + vvDist[k][j] < vvDist[i][j]){vvDist[i][j] = vvDist[i][k] + vvDist[k][j];vvParentPath[i][j] = vvParentPath[k][j];//这里为什么不直接是k呢?//首先如果k是推出j的上一个顶点,那么vvp[k][j]一定放的是k//那么如果k不是推出j的上一个顶点呢?那么就不能填k,//但是上一个顶点一定存放在vvp[k][j]里面}}}}

7.总结

这些算法都比较抽象,博主花了很大很大的功夫才理解他们,如果真要完全手撕,那么我想博主起码最少需要几个小时,因此就算不会手撕也没有关系,只需要知道思路即可。在面试中,能讲出思路也是一个加分项呢。

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

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

相关文章

Meta Reality Labs的VR/AR投资战略转向:内部视角与市场影响

最近,关于Meta(原Facebook)计划减少其在消费者虚拟现实(VR)领域的投资而增加对增强现实(AR)眼镜的投资的消息引起了广泛讨论。这一战略调整不仅反映了Meta对未来技术趋势的看法,也揭示了公司在面对激烈的市场竞争时所采取的新方向。本文将从不同角度探讨此次战略转向的…

ASP.NET Core项目中使用SqlSugar连接多个数据库的方式

之前学习ASP.NETCore及SqlSugar时都是只连接单个数据库处理数据&#xff0c;仅需在Program文件中添加ISqlSugarClient的单例即可&#xff08;如下代码所示&#xff09;。 builder.Services.AddSingleton<ISqlSugarClient>(s > {SqlSugarScope sqlSugar new SqlSugar…

flutter_quill如何设置Editor中的文字为富文本

比如一个场景 在输入框中&#xff0c;某某某 是一个颜色&#xff0c;其他文本是一个颜色 这里要注意 const QuillEditor({required this.controller,required this.focusNode,required this.scrollController,required this.scrollable,required this.padding,required this…

uniapp:封装商品列表为组件并使用

封装商品列表为组件并使用 商品组件封装 <template><!-- 商品列表 --><view class"goods_list"><view class"goods_item" v-for"item in goods" :key"item.id"><image :src"item.img_url">…

【AI系统】LLVM 架构设计和原理

LLVM 架构设计和原理 在上一篇文章中&#xff0c;我们详细探讨了 GCC 的编译过程和原理。然而&#xff0c;由于 GCC 存在代码耦合度高、难以进行独立操作以及庞大的代码量等缺点。正是由于对这些问题的意识&#xff0c;人们开始期待新一代编译器的出现。在本节&#xff0c;我们…

【C语言】结构体(二)

一&#xff0c;结构体的初始化 和其它类型变量一样&#xff0c;对结构体变量可以在定义时指定初始值 #include <stdio.h> #include <stdlib.h> struct books // 结构体类型 {char title[50];char author[50]; //结构体成员char subject[100];int book_id; }…

【docker】docker网络六种网络模式

Docker 网络模式总结 网络模式描述使用场景bridge默认的网络模式&#xff0c;容器之间通过虚拟网桥通信&#xff0c;容器与宿主机隔离。单机部署、本地开发、小型项目host容器与宿主机共享网络堆栈&#xff0c;容器直接使用宿主机的 IP 地址。高性能网络应用、日志处理、大量与…

四、初识C语言(4)

一、作业&#xff1a;static修饰局部变量 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <string.h> //作业&#xff1a;static修饰局部变量 int sum (int a) {int c 0;static int b 3;c 1;b 2;return (abc); } int main() {int i 0;int a …

【python】类方法和静态方法

类方法 通过classmethod装饰器实现 class A(object):bar 1classmethoddef class_foo(cls):print Hello, , clsprint cls.bar>>> A.class_foo() # 直接通过类来调用方法 Hello, <class __main__.A> 1在上面&#xff0c;我们使用了 classmethod 装饰方法 clas…

Linux 中的 ls 命令:从使用到源码解析

ls 命令是 Linux 系统中最常用和最基本的命令之一。下面将深入探讨 ls 命令的使用方法、工作原理、源码解析以及实际应用场景。 1. ls 命令的使用** ls 命令用于列出目录内容&#xff0c;显示文件和目录的详细信息。 1.1 基本用法 ls [选项] [文件或目录]例如&#xff1a; …

SQL 中SET @variable的使用

在 SQL 中&#xff0c;SET variable 用于声明和赋值用户定义的变量。具体来说&#xff0c; 符号用于表示一个局部变量&#xff0c;可以在 SQL 语句中存储和使用。它通常在存储过程、函数或简单的 SQL 查询中使用。 1. 声明并赋值给变量 你可以使用 SET 语句给一个变量赋值。例…

The selected directory is not a valid home for Go SDK

在idea里配置go语言的环境时&#xff0c;选择go语言的安装目录&#xff0c;一直提示这个 The selected directory is not a valid home for Go SDK后来查了一下&#xff0c;发现原来idea识别不出来 需要改一下配置文件&#xff0c;找到go环境的安装目录&#xff0c;我是默认安…

Leetcode581. 最短无序连续子数组(HOT100)

链接 我的代码&#xff1a; class Solution { public:int findUnsortedSubarray(vector<int>& nums) {vector<int> res nums;sort(res.begin(),res.end());int l 0,r nums.size()-1;while(nums[l]res[l]){l;if(lnums.size()){return 0;}}while(nums[r]res…

SQL优化与性能——数据库事务管理

数据库事务管理是数据库系统中至关重要的一部分&#xff0c;确保了数据的一致性、完整性、可靠性和隔离性。尤其在高并发、高负载的系统中&#xff0c;事务管理的设计和实现直接影响到系统的稳定性和性能。本章将详细探讨以下内容&#xff1a;事务的ACID特性、使用 BEGIN、COMM…

CentOS修改yum.repos.d源,避免“Could not resolve host: mirrorlist.centos.org”错误

1、问题现象 由于CentOS停止维护&#xff0c;mirrorlist.centos.org网站也关闭不可访问。导致CentOS默认配置的yum.repos.d源也不可用&#xff0c;所以执行yum命令会报“Could not resolve host: mirrorlist.centos.org”错误。具体如下&#xff1a; Could not retrieve mirror…

【Robocasa】Code Review

文章目录 OverviewalgoInitializationImportant Class MethodsTrain LoopTest Time ConfigsdemoConfig FactoryConfig StructureConfig Locking默认锁定状态配置修改的上下文管理器 dataset示例数据集对象参数说明 model基础模块EncoderCoreVisualCoreScanCore随机化器 (Random…

【单细胞数据库】癌症单细胞数据库CancerSEA

数据库地址&#xff1a;home (hrbmu.edu.cn) Cite Huating Yuan, Min Yan, Guanxiong Zhang, Wei Liu, Chunyu Deng, Gaoming Liao, Liwen Xu, Tao Luo, Haoteng Yan, Zhilin Long, Aiai Shi, Tingting Zhao, Yun Xiao, Xia Li, CancerSEA: a cancer single-cell state atlas…

在物联网软件开发中,常见的通信协议有哪些

在物联网 (IoT) 软件开发中&#xff0c;通信协议是关键部分&#xff0c;用于设备间以及设备与服务器之间的数据传输。以下是我收集总结的常见的通信协议及其特点&#xff1a; 1. 应用层协议 这些协议负责数据的格式化、传输和解读&#xff0c;常用于 IoT 设备与云服务或其他设…

React 的学习记录一:与 Vue 的相同点和区别

目录 一、学习目标 二、学习内容1️⃣——React的特点 1.组件化设计 2.单向数据流 3.声明式 UI 4.虚拟 DOM 5.Hooks 6.JSX 7.React Native 三、React与vue的比较总结 四、总结 一、学习目标 时间&#xff1a;两周 内容&#xff1a; React的特点React的入门React的…

深度学习-52-AI应用实战之基于Yolo8的目标检测自动标注

文章目录 1 YOLOv81.1 YOLOV8的不同版本1.2 可检测类别1.3 数据说明1.4 网络结构1.5 算法核心步骤2 目标检测的基本原理2.1 安装yolov8(cpu版本)2.2 图片检测2.3 视频检测2.4 自动标注2.5 保存标注结果3 参考附录1 YOLOv8 YOLOv8是一种前沿的计算机视觉技术,它基于先前YOLO版…