📜  Floyd Warshall 算法 | DP-16(1)

📅  最后修改于: 2023-12-03 14:41:14.513000             🧑  作者: Mango

Floyd Warshall算法 | DP-16

Floyd Warshall算法又称为插点法,是一种用于求解任意两点间最短路径的算法。该算法的时间复杂度为O(n^3),其中n为顶点数量。本文将介绍Floyd Warshall算法的思路、实现以及应用。

算法思路

Floyd Warshall算法的思路非常简单,直接从任意两点间的最短路径的定义出发:若从顶点i到顶点j的路径上只经过了k个顶点(假设为v1,v2,...,vk),则该路径的长度为dis[i][v1]+dis[v1][v2]+...+dis[vk][j],其中dis[i][j]表示i到j的距离,可以通过邻接矩阵或邻接表来表示。上述路径是i到j的一条路径,如果它的长度比dis[i][j]还短,那么我们就可以用这条路径来更新dis[i][j]的值,从而获得一个更短的路径。

我们考虑顶点k是否在i到j的路径上,如果是,则从i到j的路径可以分成两部分:i到k的路径和k到j的路径,由于我们假设所有路径的中间节点都是从1到k的,因此i到k的路径和k到j的路径都可以在dis数组中找到。如下所示:

image

因此,我们可以得到Floyd Warshall算法的核心代码如下:

for k in range(n):
    # 计算从i到j,中间经过k的路径长度
    for i in range(n):
        for j in range(n):
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j])
实现说明

算法核心代码已经给出了,我们需要注意以下几个问题:

  • 初始化:由于我们要计算的是任意两点间的最短路径,因此我们需要把每一条边的权值初始化为邻接矩阵或邻接表中对应的权值。如果不存在该边,则需要把它的权值设置为一个极大值。这个极大值通常定义为无穷大,可以使用float('inf')或sys.maxsize来表示。
  • 路径重构:我们可以利用一个二维数组path来保存每对顶点之间的最短路径中,顶点经过的前驱节点。例如,path[i][j]表示从顶点i到顶点j的最短路径上,j的前驱节点是path[i][j]。如果path[i][j]=k,则表示从i到j的最短路径经过了k。我们可以利用path数组来重构从任意顶点x到任意顶点y的最短路径,这个算法的过程类似于深度优先遍历和广度优先遍历。
应用场景

Floyd Warshall算法可以用来解决一些经典的图论问题,例如:

  • 任意两点间的最短路径
  • 任意两点间的最短距离
  • 任意两点间的最短回路

由于它的时间复杂度为O(n^3),因此适用于顶点数比较小的图。如果顶点数比较大,可以考虑使用其他的图论算法,例如Dijkstra算法或Bellman-Ford算法。

参考文献