最短路径Floyd算法图解与C++实现
邻接矩阵特征
Floyd算法建立在对图的邻接矩阵的操作上,理解Floyd首先要理解邻接矩阵
对于有向图,邻接矩阵的一行代表该顶点的出边,一列代表该顶点的入边
对于无向图则不区分出边与入边,邻接矩阵表示成一个对称矩阵
graph[i][j] 代表 i -> j ,由 i 直接到 j 的代价,graph[i][k] + graph[k][j]就表示 (i -> k) + (k -> j) ,即 i -> k -> j ,由 i 经 k 到 j 的代价
Floyd代码中有三层for循环,其中最内层for就是在操作这样一个值 + 一行值
下面以上图为例,分析Floyd算法运行过程
Floyd算法
Floyd算法中使用一个三维数组 ans[k][i][j],表示可以经过的中间结点序号小于等于 k 时,顶点 i 到顶点 j 的最小代价
① ans[0][i][j]的值即邻接矩阵
② ans[1][i][j]的值即,可以经过顶点 1 ,各顶点对间最小代价,这个值是在ans[0][i][j]的基础上得到的。
经过顶点 1 有什么好处?
以前只有 i -> j 的边能用,现在 i -> 1 -> j 的边也能用了,表现在邻接矩阵上就是,以前的代价是graph[i][j],现在可以是
graph[i][1] + graph[1][j]了,即在这个三维矩阵中ans[1][i][j]的值应该等于min{ans[0][i][j], ans[0][i][1] + ans[0][1][j]},经过这样的比较,就将顶点 1 能产生的影响考虑了进去。
③ 同上,将所有顶点都考虑进去,就得到了整个图中顶点对的最短路径
代码实现与分析
代码中实际使用的是一个二维数组ans[i][j],下面先给出代码,然后在解释代码中分析使用二维而不是三维的可行性
#include <iostream>using namespace std;
#define MAXN 110
int ans[MAXN][MAXN];int main() {int n, m; //n个顶点,序号为 1 到 n, m条边while (cin >> n >> m) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {ans[i][j] = -1; //不可达}ans[i][i] = 0;}for (int i = 0; i < m; i++) { //顶点u到顶点v,代价为wint u, v, w;cin >> u >> v >> w; //顶点从1开始编号ans[u][v] = w;ans[v][u] = w;}for (int k = 1; k <= n; k++) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {if (ans[i][k] == -1 || ans[k][j] == -1)continue;if (ans[i][j] == -1 || ans[i][j] < ans[i][k] + ans[k][j])ans[i][j] = ans[i][k] + ans[k][j];}}}}}
代码的核心就是三层for循环,三个for各有各的作用。首先要明确的是,三层for的最终目的就是要求出ans[n][i][j],ans[n][i][j]是将所有顶点能产生的影响都考虑进去时,各顶点对的最短路径。
①最内层for,k不变,i不变,j遍历所有顶点
比如k = 1,i = 3,j = 1...4,实现的是修改ans[3][j],顶点 3 到各顶点最小代价,即第三行值,考虑的是顶点k = 1的影响,顶点k = 1能对顶点 3 产生的影响就是,从顶点 3 走向顶点 1 ,再从顶点1去各顶点,这个代价与原来不考虑1的哪个小,就是
ans[3][j] = min(ans[3][1] + ans[1][j], ans[3][j]),从图上来看,3->1,应该找3行1列,再1->*,应该找1行*列,将这两步代价相加即3->*代价,图上是深蓝方块去加浅蓝方块,再与对应黄色方块比较,并修改黄色方块
最内层for修改的是,考虑需要小于k的顶点时,矩阵第i行的值,是顶点 i 考虑顶点k后的结果
②中间层for,j 遍历各个顶点,每个顶点都考虑一次顶点k产生的影响,就是顶点k对整个图产生的影响
③最外层for,k 遍历各个顶点,整个矩阵对每个顶点的影响都考虑一次,就是所有顶点对整个图产生的影响,即最终所求
二维替代三维
现在再来说明为什么能用二维数组替代三维数组
最外层for每轮要将这个二维数组所有元素修改一遍,从代码中可以看出,用来比较的,即需要其值不被随意改动的是一行一列的元素,修改其他9个白色方块时自然不会对这7个蓝色方块造成影响,而修改蓝色方块时呢?
①深蓝:即j = k,ans[i][k] = min(ans[i][k] + ans[k][k], ans[i][k]) ,ans[k][k]是自己到自己一定为0
②浅蓝:即i = k,ans[k][j] = min(ans[k][k] + ans[k][j], ans[k][j]),ans[k][k]同样为0
可以看出两种情况都不会造成影响,蓝色方块在这一轮k中是固定不变的,从算法上理解就是要考虑的中间顶点是k,如果k是两端结点,那么某个顶点经过k再到k,这个值就是这个顶点直接到k的值,另一端同理,从k经k到某个顶点=从k到某个顶点
既然没影响,自然可以在原地修改数组中的元素值
这里需要特别注意的是,最外层for每轮计算一个顶点能产生的影响,这个影响是该顶点在当前状态下能产生的直接影响,也就是顶点1能产生的影响,并不是在计算过k=1之后就固定了,只是在算法运行过程中,先把顶点1的影响加入,在后续过程中持续发挥着作用
比如,
k = 0时只将graph[i][j]考虑进去,
k = 1时将graph[i][j],graph[i][1] + graph[1][j]考虑进去
k = 2时将graph[i][j],graph[i][1] + graph[1][j],graph[i][1] + graph[1][2] + graph[2][j],graph[i][2] + graph[2][j]考虑进去,此时顶点1的影响不仅局限于k = 1那一轮计算过的graph[i][1] + graph[1][j],还有graph[i][1] + graph[1][2] + graph[2][j],先经1再经2
k = 2时看似是比较了两个值,其实是将四种路径进行比较取最小值,这样到最后一轮,就是所有路径的最小值
最短路径Floyd算法图解与C++实现相关推荐
- C++ 实现带权有向图的每对顶点之间的最短路径Floyd算法(完整代码)
基本思想是: 假设求从顶点vi到vj的最短路径. 如果从vi到vj有弧,则从vi到vj存在一条长度为arcs[i][j]的路径,该路径不一定是最短路径,尚需进行n次试探. 首先考虑路径(vi, v0, ...
- 最短路径(Floyd算法)(c/c++)
如果要得到图中各个顶点之间的最短路径,方法1:可以对每一个顶点采用Dijkstra算法:方法2:可以采用Floyd算法,它是一种用来求双源点之间最短路径的算法,采用邻接矩阵来存储图 辅助结构 int ...
- 最短路径--Floyd算法
Floyd算法 1.定义概览 Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被 ...
- 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?...
简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...
- 最短路径——Floyd算法及优化(蓝桥杯试题集)
*对最短路径问题以及floyd算法.Dijkstra算法不是很理解的同学请移步前几篇博客~ 题目链接: http://lx.lanqiao.cn/problem.page?gpid=T15 问题描述 ...
- 最短路径——Floyd算法HDU Today(hdu2112)
最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图(由结点和路径组成的)中两结点之间的最短路径. 算法具体的形式包括: 确定起点的最短路径问题 - 即已知起始结点,求最短路径的问题. 确定终点的 ...
- HDU2066 一个人的旅行【最短路径+Floyd算法】
一个人的旅行 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- 求最短路径Floyd算法的并行化(解APSP问题)
求最短路径的串行算法在互联网上应该一搜一大堆,也非常简单,几行代码搞定.但Floyd的并行算法却很难搜到,github倒是有一些,但不容易运行成功,这里对这个算法的并行化进行详细的讲解,结合论文以及实 ...
- 多源最短路径--Floyd算法
#include<iostream> #include<cstdio> using namespace std; const int INF = 0x3f3f3f3f; int ...
最新文章
- R语言使用pwr包的pwr.t2n.test函数对分组样本数不同的t检验进行效用分析(power analysis)的语法
- PHP中的PathInfo
- Oracle数据库锁诊断
- iLO4外网访问时不能启动控制台
- C语言试题三十六之将s所指字符串中所有下标为奇数位置上的字母转换为大写(若该位置上不是字母,则不转换)。
- 2020牛客国庆集训派对day4 	Arithmetic Progressions
- JEECG 3.7.8 新版表单校验提示风格使用升级方法(validform 新风格漂亮,布局简单)
- MySQL如何用一条SQL将一张表里的数据插入到另一张表
- FPGA--------随笔总结(持续更新)
- Java实现 第三方的验证码发送问题--博客园老牛大讲堂
- 个性化推荐系统实践应用
- three.js顶点篇
- 指纹识别技术的发展前景是怎样的?
- 5G技术在物联网行业的应用
- 文墨绘学呵护那一点点光
- grafana 获取禅道bug执行sql语句的问题
- 关于AndroBench在Android 10以后性能衰减的问题分析
- 【积水成渊-逐步定制自己的Emacs神器】4:Emacs自动补全
- 汽车动力系统ECU固件逆向工程初探
- 【Vue element-admin 如何给侧边栏添加 Badge 计数标记 】
热门文章
- 35岁转行,是我人生中最正确的选择
- 拼搏了3个月,工资翻了3倍多后,我哭了......
- Linux 3: Database development technology | Linux
- url中的参数带有连接符号处理 url参数带路径问题
- 前端面试问题之兼容问题
- 成都InfoComm China 2018高峰会议 开拓新商机、扩建商业网络的专业学习平台
- linux中异或符号,C的|、||、、、异或、~
- M1 Mac mini 使用半年体验 - Mac的新未来
- 脂肪酸酰胺水解酶抑制剂的研究
- 新手必备pr 2021快速入门教程「四」新建序列及参数设置