• 最短路径算法之三:多源带权图,Floyd算法,python实现


    其他图的最短路径可以看下我的这两篇:

    1、求单源无权图的最短路径,BFS算法,python实现

    2、求单源带权图最短路径,Dijkstra算法,python实现

    求多源带权图最短路径,就是求任意两个顶点的最短路径,常见的实现思路有很多种,这里介绍两种

    1. 对图所有顶点循环一遍 Dijkstra,因为一遍Dijkstra可以求到给定一个起点到任意顶点的最短路径,所以循环一遍所有顶点即可以求任意两顶点的最短路径。
    2. Floyd算法

    Floyd算法介绍

            D^{k}[i][j] 表示从顶点 Vi 到顶点 Vj 的路径上经过的顶点序号不大于 k 的最短路径长度:

                    当k=0时,D^{0}[i][j] 表示任意两个结点,仅可能经过顶点0的最短距离

                    当k=1时,D^{1}[i][j] 表示任意两个结点,仅可能经过顶点0、1的最短距离

                    当k=k-1时,D^{k-1}[i][j] 表示任意两个结点,仅可能经过顶点0、1、...、k-1的最短距离

                    当k=k时,D^{k}[i][j] 表示任意两个结点,全图的最短距离

            可见,当k=顶点数时,我们即可以求得任意两个顶点的全图最短距离,否则只能求到k-i个顶点的最短距离,不是真正的最短距离。

            当D^{k-1} 已经完成,递推到D^{k}时:

                    如果 Vi -> Vj 的最短路径不经过 k,那么D^{k}=D^{k-1}

                    反之, 如果 Vi -> Vj 的最短路径经过 k,即 { i -> { l<=k } > j } ,那么这条路径必然由两部分组成  D^{k}[i][j] = D^{i-1}[i][k] + D^{i-1}[k][j]

    代码实现:

    1. class Floyd(IVisitGraph):
    2. INFINITY = 9999999
    3. def __init__(self):
    4. super(Floyd, self).__init__()
    5. self.dist = [[]] # dist矩阵 存储i->j的最短路径
    6. def initVisted(self, g):
    7. """
    8. g: 图,矩阵实现
    9. """
    10. super(Floyd, self).initVisted(g)
    11. self.dist = [ [-1 for i in range(g.nV)] for j in range(g.nV)]
    12. for i in range(g.nV):
    13. for j in range(g.nV):
    14. if j == i:
    15. self.dist[i][j] = 0
    16. elif g.G[i][j] < 0: # 没有边的情况下要更新为无穷大,因为选最短路径
    17. self.dist[i][j] = self.INFINITY
    18. else: # 有边则更新为权重
    19. self.dist[i][j] = g.G[i][j]
    20. def visit(self, g, v: int):
    21. """
    22. 佛洛伊德算法,解决图的多源最短路问题
    23. """
    24. self.g = g
    25. # 显然时间复杂度V^3
    26. for k, v in enumerate(range(g.nV)):
    27. for i, v in enumerate(range(g.nV)):
    28. for j, v in enumerate(range(g.nV)):
    29. # 是否存在顶点K,导致 i->k->j 才是i->j的最短路径
    30. # self.dist[i][j] 上一次 D(k-1) 的最短距离
    31. # k 影响因子
    32. if (self.dist[i][j] > self.dist[i][k]+self.dist[k][j]):
    33. self.dist[i][j] = self.dist[i][k]+self.dist[k][j]

    以下图为例,拆分一下 D^{k}

    未开始Dloyd时,进行初始化工作,D^{-1} 为边矩阵,顶点自己到自己的距离为0,其余为邻接边的权重、如果两个顶点之间没有边则设置一个 INFINITY 值。

    •  以V1为例,V1到V1 dist为0;V1到V2有边,dist值为2;V1到V3没有边(有向),dist为无穷大.....

    现在进行第一次遍历, k=0,D^{0},表示仅可能经过顶点V1的最短路径,此时D^{0} 具体数值如下

    • 经过V1后,V3到V2连通了;V3到V4连通了;请注意此时不是最短路径。

    现在进行第二次遍历, k=1,D^{1},表示仅可能经过顶点V1,V2的最短路径,此时D具体数值如下

    • V2加入后,V1到V5连通了;V3到V5也连通了;请注意此时不是最短路径。 

    现在进行第三次遍历, k=2,D^{2},表示仅可能经过顶点V1,V2,V3的最短路径,此时D具体数值如下

    • 看起来没什么变化,因为能和V3连通必须和V4连通,现在V4还没有加进来

    现在进行第四次遍历, k=3,D^{3},表示仅可能经过顶点V1,V2,V3,V4的最短路径,此时D具体数值如下 

    •  随着V4的加入,不少路都连通了,并且路径也变短了。这恰恰说明了只有当k等于顶点数时,才是真正的最短路径,前面的只能说算是“连通路径”

    后面不逐步解释了,只是体会一下随着结点的加入,两点之间路径的变化效果。最后展示一下当k=6时,D^{6},表示全图的最短路径。此时最短路径如下

     

     

  • 相关阅读:
    Haskell使用了map/filter和zip来实现功能的例子
    私域流量的变现方式,你知道多少?
    渲染器——双端Diff算法
    Pandas处理异常值的两种方法
    交换机和路由器技术-13-三层交换
    猿创征文 | 开箱即用 yyg-cli:快速创建 vue3 组件库和vue3 全家桶项目
    docker安装mysql-简单无坑
    R语言统计学DOE实验设计:用平衡不完全区组设计(BIBD)分析纸飞机飞行时间实验数据...
    ELK 企业级日志分析系统
    进阶vue面试题总结
  • 原文地址:https://blog.csdn.net/weixin_40647516/article/details/126279861