0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Floyd如何求图的最短路径

算法与数据结构 ? 来源:bigsai ? 作者:大赛 ? 2021-10-09 14:38 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

前言

图论中,在寻路最短路径中除了Dijkstra算法以外,还有Floyd算法也是非常经典,然而两种算法还是有区别的,Floyd主要计算多源最短路径

在单源正权值最短路径,我们会用Dijkstra算法来求最短路径,并且算法的思想很简单—贪心算法:每次确定最短路径的一个点然后维护(更新)这个点周围点的距离加入预选队列,等待下一次的抛出确定。虽然思想很简单,实现起来是非常复杂的,我们需要邻接矩阵(表)储存长度,需要优先队列(或者每次都比较)维护一个预选点的集合。还要用一个boolean数组标记是否已经确定、还要……

总之,Dijkstra算法的思想上是很容易接受的,但是实现上其实是非常麻烦的。但是单源最短路径解算暂时还没有有效的办法,复杂度也为O(n2)

而在n点图中想求多源最短路径,如果从Dijkstra算法的角度上,需要将Dijkstra执行n次才能获得所有点之间的最短路径,不过执行n次Dijkstra算法即可,复杂度为O(n3)。但是这样感觉很臃肿,代码量巨大,占用很多空间内存。有没有啥方法能够稍微变变口味呢?

答案是有的,今天就带大家一起了解一下牛逼轰轰的Floyed算法。

算法介绍

什么是Floyed算法?

Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授罗伯特·弗洛伊德命名。

简单的来说,算法的主要思想是动态规划(dp),而求最短路径需要不断松弛(熟悉spfa算法的可能熟悉松弛)。

而算法的具体思想为:

1 .邻接矩阵(二维数组)dist储存路径,数组中的值开始表示点点之间初始直接路径,最终是点点之间的最小路径,有两点需要注意的,第一是如果没有直接相连的两点那么默认为一个很大的值(不要因为计算溢出成负数),第二是自己和自己的距离要为0。

2 .从第1个到第n个点依次加入松弛计算,每个点加入进行试探枚举是否有路径长度被更改(自己能否更新路径)。顺序加入(k枚举)松弛的点时候,需要遍历图中每一个点对(i,j双重循环),判断每一个点对距离是否因为加入的点而发生最小距离变化,如果发生改变(变小),那么两点(i,j)距离就更改。

2 .重复上述直到最后插点试探完成。

其中第2步的状态转移方程为:

dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j])

其中dp[a][b]的意思可以理解为点a到点b的最短路径,所以dp[i][k]的意思可以理解为i到k的最短路径dp[k][j]的意思为k到j的最短路径.

咱们图解一个案例,初始情况每个点只知道和自己直接相连的点的距离,而其他间接相连的点还不知道距离,比如A-B=2,A-C=3但是B-C在不经过计算的情况是不知道长度的。

03956320-21de-11ec-82a8-dac502259ad0.png

加入第一个节点A进行更新计算,大家可以发现,由于A的加入,使得本来不连通的B,C点对和B,D点对变得联通,并且加入A后距离为当前最小,同时你可以发现加入A其中也使得C-D多一条联通路径(6+3),但是C-D联通的话距离为9远远大于本来的(C,D)联通路径2,所以这条不进行更新。

03fc0972-21de-11ec-82a8-dac502259ad0.png

咱们继续加入第二个节点B,这个点执行和前面A相同操作进行。对一些点进行更新。因为和B相连的点比较多,可以产生很多新的路径,这里给大家列举一下并做一个说明,这里新路径我统一用1表示,原来长度用0表示。

AF1=AB+BF=6+2=8 < AF0(∞) 进行更新

AE1=AB+BE=2+4=6 < AE0(∞) 进行更新

CE1=CB+BE=5+5=9 < CE0(∞) 进行更新

CF1=CB+BF=5+6=11

EF1=EB+BF=4+6=10

当然,也有一些新的路径大于已有路径不进行更新,例如:

AC1=AB+BC=2+5=7>AC0(3)不更新

AD1=AB+BD=2+8=10>AD0(6)不更新

……

更多路径这里就不一一列举了。

04156728-21de-11ec-82a8-dac502259ad0.png

后序加入C、D、E、F都是进行相同的操作,最终全部加完没有路径可以更新就结束停止。实际上这个时候图中的连线就比较多了。这些连线都是代表当前的最短路径。这也和我们的需求贴合,我们最终要的是所有节点的最短路径。每个节点最终都应该有5条指向不同节点的边!矩阵对应边值就是点点之间最短路径。

至于算法的模拟两部核心已经告诉大家了,大家可以自行模拟剩下的。

程序实现

而对于程序而言,这个插入的过程相当简单。核心代码只有四行!这个写法适合有向图和无向图,无向图的算法优化后面会说。
代码如下

publicclassfloyd{
staticintmax=66666;//别Intege.max两个相加越界为负
publicstaticvoidmain(String[]args){
intdist[][]={
{0,2,3,6,max,max},
{2,0,max,max,4,6},
{3,max,0,2,max,max},
{6,max,2,0,1,3},
{max,4,max,1,0,max},
{max,6,max,3,max,0}};//地图
//6个
for(intk=0;k6;k++)//加入第k个节点进行计算
{
for(inti=0;i6;i++)//每加入一个点都要枚举图看看有没有可以被更新的
{
for(intj=0;j6;j++)
{
dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);
}
}
}
//输出
for(inti=0;i6;i++){
System.out.print("节点"+(i+1)+"的最短路径");
for(intj=0;j6;j++){
System.out.print(dist[i][j]+"");
}
System.out.println();
}
}
}

执行结果为:

046ca16e-21de-11ec-82a8-dac502259ad0.png

可以自行计算,图和上篇的Dijkstra用的图是一致的,大家可以自行比对,结果一致,说明咱么的结果成功的。

当然,在你学习的过程中,可以在每加入一个节点插入完成后,打印邻接矩阵的结果,看看前两部和笔者的是否相同(有助于理解),如果相同,则说明正确!

对于加入点更新你可能还是有点疑惑其中的过程,那咱么就用一个局部来演示一下帮助你进一步理解Floyd算法,看其中AB最短距离变化情况祝你理解:

048f261c-21de-11ec-82a8-dac502259ad0.png

小试牛刀

自己会没会?刷一道题就可以知道了,刚好力扣1334是一道Floyd算法解决的问题。

题目描述为

有 n 个城市,按从 0 到 n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromi 和 toi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold。

返回能通过某些路径到达其他城市数目最少、且路径距离 最大 为 distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 i 和 j 的路径的距离等于沿该路径的所有边的权重之和。

示例1:

04f14626-21de-11ec-82a8-dac502259ad0.png

输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2]
城市 1 -> [城市 0, 城市 2, 城市 3]
城市 2 -> [城市 0, 城市 1, 城市 3]
城市 3 -> [城市 1, 城市 2]
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例2:

050456d0-21de-11ec-82a8-dac502259ad0.png

输入:n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
输出:0
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1]
城市 1 -> [城市 0, 城市 4]
城市 2 -> [城市 3, 城市 4]
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3]
城市 0 在阈值距离 2 以内只有 1 个邻居城市。

提示:

2 <= n <= 100
1 <= edges.length <= n * (n - 1) / 2
edges[i].length == 3
0 <= fromi < toi < n
1 <= weighti, distanceThreshold <= 10^4
所有 (fromi, toi) 都是不同的。

思路分析:

拿到一道题,首先就是要理解题意,而这道题的意思借助案例也是非常能够理解,其实就是判断在distanceThreshold范围内找到能够到达的最少点的编号,如果多个取最大即可。正常求到达最多情景比较多这里求的是最少的,但是思路都是一样的。

这道题如果使用搜索,那复杂度就太高了啊,很明显要使用多源最短路径Floyd算法,具体思路为;

1 .先使用Floyd算法求出点点之间的最短距离,时间复杂度O(n3)

2 . 统计每个点与其他点距离在distanceThreshold之内的点数量,统计的同时看看是不是小于等于已知最少个数的,如果是,那么保存更新。

3 .返回最终的结果。

实现代码:

classSolution{
publicintfindTheCity(intn,int[][]edges,intdistanceThreshold){
intdist[][]=newint[n][n];
for(inti=0;ifor(intj=0;j//保证数据比最大二倍大(两相加不能比它大),并且不能溢出,不要Int最大相加为负会出错
dist[i][j]=1000000;
}
dist[i][i]=0;
}
for(intarr[]:edges){
dist[arr[0]][arr[1]]=arr[2];
dist[arr[1]][arr[0]]=arr[2];
}
for(intk=0;kfor(inti=0;ifor(intj=0;jintmin=Integer.MAX_VALUE;
intminIndex=0;
intpathNum[]=newint[n];//存储距离
for(inti=0;ifor(intj=0;jif(dist[i][j]<=distanceThreshold){
????????????????????pathNum[i]++;
????????????????}
????????????}
????????????if(pathNum[i]<=min)?{
????????????????min?=?pathNum[i];
????????????????minIndex=i;
????????????}
????????}
????????returnminIndex;

}
}

那么想一下优化空间:Floyd算法还有优化空间嘛?

有的,这个是个无向图,也就是加入点的时候枚举其实会有一个重复的操作过程(例如枚举AC和CA是效果一致的),所以我们在Floyd算法的实现过程中过滤掉重复的操作,具体代码为:

classSolution{
publicintfindTheCity(intn,int[][]edges,intdistanceThreshold){
intdist[][]=newint[n][n];//存储距离
for(inti=0;ifor(intj=0;j1000000;
}
dist[i][i]=0;
}
for(intarr[]:edges){
dist[arr[0]][arr[1]]=arr[2];
dist[arr[1]][arr[0]]=arr[2];
}
for(intk=0;kfor(inti=0;ifor(intj=i+1;j//去掉重复的计算
dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);
dist[j][i]=dist[i][j];
}
}
}
intmin=Integer.MAX_VALUE;
intminIndex=0;
intpathNum[]=newint[n];//
for(inti=0;ifor(intj=0;jif(dist[i][j]<=distanceThreshold){
????????????????????pathNum[i]++;
????????????????}
????????????}
????????????if(pathNum[i]<=min)?{
????????????????min?=?pathNum[i];
????????????????minIndex=i;
????????????}
????????}
????????returnminIndex;

}
}

尾声

对于Floyd算法,如果初次接触不一定能够理解这个松弛的过程。

Floyd像什么呢,最终最短路径大部分都是通过计算得到而存储下来直接使用的,我觉得它和MySQL视图有点像的,视图是一个虚表在实表上计算获得的,但是计算之后各个数据就可以直接使用,Floyd是在原本的路径图中通过一个动态规划的策略计算出来点点之间的最短路径。

FloydDijkstra是经典的最短路径算法,两者有相似也有不同。在复杂度上,Dijkstra算法时间复杂度是O(n2),Floyd算法时间复杂度是O(n3);在功能上,Dijkstra是求单源最短路径,并且路径权值不能为负,而Floyd是求多源最短路径,可以有负权值;算法实现上,Dijkstra 是一种贪心算法实现起来较复杂,Floyd基于动态规划实现简单;两个作者DijkstraFloyd都是牛逼轰轰的大人物,都是图灵奖的获得者。

除了Floyd算法,堆排序算法heapSort也是Floyd大佬发明的,属实佩服!

Floyd算法,俗称插点法,不就一个点一个点插进去更新用到被插点距离嘛!

好啦,Floyd算法就介绍到这里,如果对你有帮助,请动动小手点个赞吧!蟹蟹。

编辑:jq
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 代码
    +关注

    关注

    30

    文章

    4913

    浏览量

    71422
  • Floyd
    +关注

    关注

    0

    文章

    2

    浏览量

    979

原文标题:Floyd是咋求图的最短路径?

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    光缆会短路

    光缆不会短路,其工作原理和结构特性决定了它与传统电缆在短路问题上的本质区别。以下是具体分析: 1. 光缆的传输介质是光,而非电 传统电缆:通过金属导线(如铜、铝)传输电信号,电流在导体中流动。若导体
    的头像 发表于 08-13 10:50 ?163次阅读
    光缆会<b class='flag-5'>短路</b>吗

    IGBT短路振荡的机制分析

    绝缘栅双极型晶体管(IGBT)在电机驱动和电器控制等多种工业领域中广泛应用。IGBT在具有更低的开关损耗的同时,还要同时具备一定的抗短路能力。短路时,如果发生短路振荡(SCOs)现象,IGBT的抗
    的头像 发表于 08-07 17:09 ?2437次阅读
    IGBT<b class='flag-5'>短路</b>振荡的机制分析

    关于电动机“相间短路”与“对地短路”的问题

    电动机作为现代工业的核心动力设备,其运行稳定性直接关系到生产效率和设备安全。在电机故障中,“相间短路”和“对地短路”是最常见的两类电气故障,其成因复杂且危害性大。本文将深入分析这两种短路现象的机理
    的头像 发表于 07-01 11:08 ?1413次阅读

    贴片电容短路的原因探析

    贴片电容作为现代电子设备中不可或缺的元件,广泛应用于各类电路中,发挥着滤波、储能、耦合和去耦等关键作用。然而,在使用过程中,贴片电容有时会出现短路故障,这不仅会影响电路的正常工作,甚至可能导致整个
    的头像 发表于 03-19 15:28 ?1306次阅读
    贴片电容<b class='flag-5'>短路</b>的原因探析

    何时选择OSPF作为路由协议

    在构建网络时,选择合适的路由协议对于确保网络的高效性和稳定性至关重要。OSPF(开放最短路径优先)是一种广泛使用的内部网关协议,特别适合于大型、复杂或多路径的网络环境。本文将探讨何时选择OSPF作为路由协议,并分析其优势和其他路由协议的对比。
    的头像 发表于 03-18 09:14 ?706次阅读
    何时选择OSPF作为路由协议

    短路保护和过载保护有什么区别?

    短路保护和过载保护是电气系统中两种重要的保护措施,它们在确保设备安全、稳定运行方面起着至关重要的作用。尽管两者都涉及到电流的异常增大,但它们的工作原理、应用场景以及实现方式存在显著的差异。本文将从
    的头像 发表于 03-10 12:07 ?2206次阅读

    上电投后DLPA3000烧毁,LED_ANOD和地短路怎么解决?

    实验环境: 1.DLP3010+DLPA3000+DLPC3478 2.上电投后DLPA3000烧毁,LED_ANOD和地短路 3.当时只接了蓝灯BLU_CATHODE,RED_CATHODE
    发表于 02-25 06:30

    ADS1211获取四个通道全部数据的最短时间是多少?

    看pdf没看出什么门道,想问下这款ADC四个差分通道同步采样,获取四个通道全部数据的最短时间是多少!
    发表于 02-10 07:24

    短路的原因和解决方法 断路的常见故障排除

    一、短路的原因 短路是指电路中的两个节点之间通过一个低阻抗的通路,使电流绕过正常的电路路径,直接从一个节点流向另一个节点,导致电路发生异常的现象。短路通常是由以下原因引起的: 电路元件
    的头像 发表于 01-31 11:11 ?7140次阅读

    什么是爬电距离与电气间隙?

    义爬电距离,可形象理解为一蚂蚁沿绝缘材料表面从一导电部件爬至另一导电部件所经最短路径。它涉及两个导电部件间沿绝缘材料表面测量的最短空间距离,这一距离的设定需综合考量电气设备的额定电压、绝缘材料的耐泄
    的头像 发表于 01-16 23:05 ?1421次阅读
    什么是爬电距离与电气间隙?

    DAC8760上电就短路,为什么?

    DAC8760上电就短路是照参考设计改的检查好多遍了找不出问题谢谢
    发表于 12-05 06:48

    DAC81402输出两个点的时间间隔,最短多少?

    输出两个点的时间间隔,最短多少? 我看时钟是50MHz
    发表于 11-22 10:51

    多台仓储AGV协作全局路径规划算法的研究

    多AGV动态路径规划需解决冲突避免,核心在整体协调最优。规划时考虑道路设计、拥堵、最短路径和交通管制,用A*算法避免重复路径和转弯,同时需交通管制防相撞。创新响应需求是关键,良好路径
    的头像 发表于 10-28 17:38 ?950次阅读
    多台仓储AGV协作全局<b class='flag-5'>路径</b>规划算法的研究

    什么是开放最短路径优先 (OSPF)?

    OSPF是一种典型的链路状态路由协议,一般在同一个路由域中使用。这里的路由域指的是一个自治系统(AS),是指一组通过统一的路由策略或协议相互交换路由信息的网络。
    的头像 发表于 10-18 17:47 ?663次阅读

    IGBT短路耐受时间的重要性

    IGBT等功率器件具有称为“短路耐受时间(SCWT:Short Circuit Withstand Time)”的电气特性(参数)。通常,在IGBT等功率元器件处于短路状态时,会流过大电流并在短时间
    的头像 发表于 10-08 17:12 ?1157次阅读
    IGBT<b class='flag-5'>短路</b>耐受时间的重要性