【数据结构】图——最短路径

最短路径问题:从在带权有向图G中的某一顶点出发,找出一条通往另一顶点的最短路径,最短也就是沿路径各边的权值总和达到最小。

最短路径分为图中单源路径和多源路径。

本文会介绍Dijkstra和Bellman-Ford解决单源路径的问题

Floyd-Warshall解决多路径的问题

单源最短路径--Dijkstra算法

单源问题,对于图中给定的结点u,求出到达各个结点v的路径代价和最小。最小路径可能是直接u->v

也可能是从u->t->v  。

Dijkstra算法就是解决所有边非负权值的最短路径。一般是从给出点u到终点v.

算法的思路

将图中的所有结点可以分为S和Q,S是已经确定最短路径的集合,Q是还没被访问的集合)(初始化时,将s放到集合中)

每一次从Q中选出一个s到Q代价最小的点u,把u从s移出放到S中,对u的相邻v 进行松弛更新。

松弛更新:判断s->u(已经确定了)  u->v的路径是否小于s->v(已经确定的)

如果是的话,就更新s->v

直到更新所有的Q结点

在我们的模拟实现中

保存一张dist[]数组,用来表示s到某点的最短路径

S[]数组用来表示已经确定最短路径的顶点、

pPath用来存储路径前一个顶点的下标

通过画图梳理这个过程

首次初始化时,dist数组s位置是0,其它为无穷,pPath数组s位置是缺省值

第二轮:寻找最短路径s-s 松弛更新出s->t s->y

第三步 选出最小v  s->y(s->s已经被标记过)

松弛更新出s-y-t s-y-x s-y-z

第三轮选边 选出s->z 对z相邻的边松弛更新

s->z->x(13)

s->z->s(14 不更新)

第四轮

选边s->t

第五轮 选出s->x 松弛更新出 x->z(不更新,已经是最短路径)

松弛更新不适合用于带负权值的路径

因为无法确定第一轮的最小值

		void Dijkstra(const V& src, vector<W>& dist, vector<int>& pPath){size_t srci = GetVertexIndex(src);size_t n = _vertexs.size();dist.resize(n, MAX_W);pPath.resize(n, -1);//自身就是0dist[srci] = W();pPath[srci] = srci;//标记容器vector<bool> S(n, false);for (size_t j = 0; j < n; j++){int u = 0;W min = MAX_W;for (size_t i = 0; i < n; i++){if (S[i] == false && dist[i] < min){u = i;min = dist[i];}}S[u] = true;//松弛更新for (size_t v = 0; v < n; v++){if (S[v] == false && _matrix[u][v] != MAX_W &&dist[u] + _matrix[u][v] < dist[v]){dist[v] = dist[u] + _matrix[u][v];pPath[v] = u;}}}}

单源最短路径--Bellman-Ford算法
 

迪杰斯特拉算法不能解决带负权值边的最短路径,贝尔曼福特就采用暴力的方式解决了带负权值边的路径问题,还能判断出回路是否带有负权值。

贝尔曼福特算法的思路是将 srci-> j的路径问题划分为srci-> i  i->j的路径最短问题

对于从源顶点 s  到目标顶点 j 的路径来说,如果存在从源顶点 s 到顶点 i 的路径,还存在一条从顶点 i  到顶点 j  的边,并且其权值之和小于当前从源顶点 s  到目标顶点 j 的路径长度,则可以对顶点 j j 的估计值和前驱顶点进行松弛更新。

是利用已经确定的最短路径srci -i 再加上i->j的边权来更新的最短路径。

确定完所有的顶点后,都必须重新进行更新,因为每一条路径的确定,都有可能影响前一轮的路径更新。故需要遍历K次。K为N次。(因为所有的点都在变,都需要更新。)

初始化时,dist[srci]初始化为缺省值

第一次i==0时,更新出t y

第二次,i==1更新出x z 

i==2时,更新出 x s(不更新,目前是最短路径)

i==3时,更新出t->z

i==4时,用x更新出t

结束第一轮

此时还需要进行下一轮的更新

下一轮再i==3时,更新出t->z=-4

		bool BellmanFord(const V& src, vector<W>& dist, vector<int>& pPath){size_t n = _vertexs.size();size_t srci = GetVertexIndex(src);dist.resize(n, MAX_W);pPath.resize(n, -1);dist[srci] = W();//最多更新k轮for (size_t k = 0; k < n; k++){bool updata = false;cout << "更新第:" << k << "轮" << endl;//srci->i+i->jfor (size_t i = 0; i < n; i++){for (size_t j = 0; j < n; j++){if (_matrix[i][j] != MAX_W && dist[i] + _matrix[i][j] < dist[j]){updata = true;cout << _vertexs[i] << "->" << _vertexs[j] << ":" << _matrix[i][j] << endl;dist[j] = dist[i] + _matrix[i][j];pPath[j] = i;}}}if (!updata)break;}//如果还能更新,就是带负路径for (size_t i = 0; i < n; i++){for (size_t j = 0; j < n; j++){if (_matrix[i][j] != MAX_W && dist[i] + _matrix[i][j] < dist[j]){return false;}}}return true;}

利用程序编写过程和我们的画图一致

贝尔曼福特算法是暴力求解,有相当高的时间复杂度O(N^3),但是能够解决负权值问题。


多源最短路径--Floyd-Warshall算法

Floyd-Warshall算法是解决任意两点间的最短路径的一种算法。

弗洛伊德算法考虑的是中间最短路径的中间结点,设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}取得的一条最短路径。

Floyd-Warshall算法是一种动态规划算法,其运行时间为o(n^3)与最短路径路径上通常的假设一样,假设权重可以为负,但不能有权重为负的环路

如果存在从顶点 i  到顶点 k  的路径,还存在从顶点 k  到顶点 j  的路径,并且这两条路径的权值之和小于当前从顶点 i 到顶点 j 的路径长度,则可以对顶点 j  的估计值和前驱顶点进行松弛更新。

算法原理:

费洛伊徳算法就是将最短路径分成dist[i][k]+ dist[k][j]与dist[k][j]的问题

算法需要一个二维的vvdist记录最短路径,vvpPath标记父路径

将直接相连的视作最短路径 

进行k次更新(K为n,i和j都在变换)

动态规划更新vvdist

注意vvpPath[i][j]的前一个不再是i而应该是递归的vvpPath[k][j],可能变化一次,也可能变化好多次

		void FloydWarshall(vector<vector<W>>& vvDist, vector<vector<int>>& vvpPath){size_t n = _vertexs.size();vvDist.resize(n, vector<W>(n, MAX_W));vvpPath.resize(n, vector<int>(n, -1));//更新权值和父路径for (size_t i = 0; i < n; i++){for (size_t j = 0; j < n; j++){if (_matrix[i][j] != MAX_W){vvDist[i][j] = _matrix[i][j];vvpPath[i][j] = i;}if (i == j){vvDist[i][j] = W();}}}//O(N^3)//最多更新k次for (size_t k = 0; k < n; k++){for (size_t i = 0; i < n; i++){for (size_t j = 0; j < n; j++){//存在 i->k  k->j 且<dist[i][j]if (vvDist[i][k] != MAX_W && vvDist[k][j] != MAX_W&& vvDist[i][k] + vvDist[k][j] < vvDist[i][j]){vvDist[i][j] = vvDist[i][k] + vvDist[k][j];vvpPath[i][j] = vvpPath[k][j];}}}// 打印权值和路径矩阵观察数据for (size_t i = 0; i < n; ++i){for (size_t j = 0; j < n; ++j){if (vvDist[i][j] == MAX_W){//cout << "*" << " ";printf("%3c", '*');}else{//cout << vvDist[i][j] << " ";printf("%3d", vvDist[i][j]);}}cout << endl;}cout << endl;for (size_t i = 0; i < n; ++i){for (size_t j = 0; j < n; ++j){//cout << vvParentPath[i][j] << " ";printf("%3d", vvpPath[i][j]);}cout << endl;}cout << "=================================" << endl;}}

最短路径的总结

迪杰斯特拉算法是基于贪心算法设计,解决非负数权值的路径问题。将顶点分为S和Q,每次都从Q中选出最小的权值u放到s中,然后将u的相邻边进行松弛调整。

贝尔曼福特算法是暴力求解,能求解出带负权值的路径,能判断负权环路。是一个时间复杂度为o(N^3)的算法。要进行K次松弛调整。每一次都是通过dist[i]+_matrix[i][j]更新权值

费洛伊徳算法是动态规划的思想,将路径分为i->k k->j的思想。同样要进行K轮次的更新。复杂度为0(N^3)。能够求解任意俩顶点的最短路径。

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

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

相关文章

来看大厂如何设计运营后台系统的?

0 背景 重运营的应用。对于App里的顶导航、我的页面、弹窗等&#xff0c;需要根据模式、版本、平台、语言、渠道等不同的维度进行运营管理。随着业务快速发展&#xff0c;版本快速迭代&#xff0c;如何&#xff1a; 保持运营资源能够被高效、稳定和灵活地配置高效稳定的为新的…

【洛谷千题详解】P1031 均分纸牌

目录 题目描述 思路点拨 AC代码 题目描述 题目网址&#xff1a;[NOIP2002 提高组] 均分纸牌 - 洛谷 有 N 堆纸牌&#xff0c;编号分别为 1,2,……,N。每堆上有若干张&#xff0c;但纸牌总数必为 N 的倍数。可以在任一堆上取若干张纸牌&#xff0c;然后移动。 移牌规则为&a…

YOLO如何训练自己的模型

目录 步骤 一、打标签 二、数据集 三、跑train代码出模型 四、跑detect代码出结果 五、详细操作 步骤 一、打标签 &#xff08;1&#xff09;在终端 pip install labelimg &#xff08;2&#xff09;在终端输入labelimg打开 如何打标签&#xff1a; 推荐文章&#xf…

代码随想录算法训练营day27|39. 组合总和、40.组合总和II

39. 组合总和 如下树形结构如下&#xff1a; 选取第二个数字5之后&#xff0c;剩下的数字要从5、3中取数了&#xff0c;不能再取2了&#xff0c;负责组合就重复了&#xff0c;注意这一点&#xff0c;自己做的时候没想明白这一点 如果是一个集合来求组合的话&#xff0c;就需…

找游戏 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 小扇和小船今天又玩起来了数字游戏&#xff0c; 小船给小扇一个正整数 n&#xff08;1 ≤ n ≤ 1e9&#xff09;&#xff0c;小扇需要找到一个比 n 大的数字 m&a…

算法 给定N个整数序列{A1,A2,....,An}求所有子序列之和的最大值

今天 &#xff0c; 开始学习算法 &#xff0c; 以这个列子解释复杂度对算法的影响 #include <stdio.h> int main() { int i 0; int arr[8] { -1,2,-3,4,-4,7,8,9 }; int j 0; int k 0; int sum 0; int max_sum 0; for( i 0 ; i < …

c#中使用devexpress gridcontrol 获取排序后的gridview数据

//获取排序后的DataTable DataTable _dt lvwItems.GridControl.DataSource as DataTable; DataTable table _dt.Clone(); for (int i 0; i < lvwItems.RowCount; i) { if (lvwItems.IsGroupRow(i)) …

如何增加层次厚度?

Q 老师&#xff0c;我在做一个斧头武器&#xff0c;如何在平面上增加厚度和层次呢&#xff1f; A 选中这几个线&#xff0c;点连接就会出现中线&#xff0c;把中线稍作调整即可~

glTF 添加数据属性(extras)

使用3D 模型作为可视化界面的一个关键是要能够在3D模型中添加额外的数据属性&#xff0c;利用这些数据属性能够与后台的信息模型建立对应关系&#xff0c;例如后台信息模型是opcua 信息模型的话&#xff0c;在3D模型中要能够包含OPC UA 的NodeId&#xff0c;BrowserName 等基本…

wcf 简单实践 数据绑定 数据校验

1.概要 1.1 说明 数据校验&#xff0c;如果数据不合适&#xff0c;有提示。 1.2 要点 class User : IDataErrorInfothis.DataContext user;<Window.Resources><Setter Property"ToolTip" Value"{Binding RelativeSource{RelativeSource Self},Pat…

3.WEB渗透测试-前置基础知识-快速搭建渗透环境(上)

上一个内容&#xff1a;2.WEB渗透测试-前置基础知识-web基础知识和操作系统-CSDN博客 1.安装虚拟机系统 linux Kali官网下载地址&#xff1a; https://www.kali.org/get-kali/#kali-bare-metal Centos官网下载地址&#xff1a; https://www.centos.org/download/ Deepin官网下…

外包干了3个月,技术倒退1年。。。

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

5555555官方v给

☞ 通用计算机启动过程 1️⃣一个基础固件&#xff1a;BIOS 一个基础固件&#xff1a;BIOS→基本IO系统&#xff0c;它提供以下功能&#xff1a; 上电后自检功能 Power-On Self-Test&#xff0c;即POST&#xff1a;上电后&#xff0c;识别硬件配置并对其进行自检&#xff0c…

AES 和 MD5

当涉及到数据安全时&#xff0c;常用的加密算法包括 AES 和 MD5。以下是对它们的简要介绍&#xff1a; AES&#xff08;Advanced Encryption Standard&#xff09;&#xff1a;AES 是一种对称加密算法&#xff0c;被广泛应用于保护数据的传输和存储安全。AES 加密使用相同的密钥…

记录realsense包编译出错的问题

我是ros1...但是下载的包好像适用于ros2 合适的下载地址&#xff1a; ROS1 打开图中所选地址 https://github.com/IntelRealSense/realsense-ros/blob/ros1-legacy/README.md#installation-instructions 版本选择ros1 下载到对应位置即可

牛客周赛 Round 34 解题报告 | 珂学家 | 构造思维 + 置换环

前言 整体评价 好绝望的牛客周赛&#xff0c;彻底暴露了CF菜菜的本质&#xff0c;F题没思路&#xff0c;G题用置换环骗了50%, 这大概是唯一的亮点了。 A. 小红的字符串生成 思路: 枚举 a,b两字符在相等情况下比较特殊 a, b input().split() if a b:print (2)print (a)pri…

【监控】grafana图表使用快速上手

目录 1.前言 2.连接 3.图表 4.job和path 5.总结 1.前言 上一篇文章中&#xff0c;我们使用spring actuatorPrometheusgrafana实现了对一个spring boot应用的可视化监控。 【监控】Spring BootPrometheusGrafana实现可视化监控-CSDN博客 其中对grafana只是打开了一下&am…

【数据结构与算法】(22)高级数据结构与算法设计之 Divide and Conquer 分治法 代码示例与详细讲解

目录 4.4 Divide and Conquer1) 概述二分查找快速排序归并排序合并K个排序链表 - LeetCode 23对比动态规划 2) 快速选择算法数组中第k个最大元素-Leetcode 215数组中位数 3) 快速幂-Leetcode 504) 平方根整数部分-Leetcode 695) 至少k个重复字符的最长子串-Leetcode 395 4.4 Di…

云原生之API网关Traefik

1. 前言 说到web服务的开源网关&#xff0c;我首先想到的是Nginx&#xff0c;最早使用的就是它&#xff0c;现在都还在使用它。系统上线了Docker Swarm集群之后&#xff0c;不继续使用Nginx直接做Docker服务的网关&#xff0c;是因为Nginx毕竟比Docker Swarm出现的早&#xff0…

简单实现文字滚动效果-CSS版本

先看看效果 话不多说直接上代码 <template><div class"main"><div class"scroll-region"><div class"swiper-scroll-content"><span class"list-btn" v-for"(item, index) in overviewList" :…