Floyd最短路径算法

使用带权图的邻接矩阵方法表示图并且不能有负周期。如:

g = [
    [0,1,float('inf'),1,5],
    [9,0,3,2,float('inf')],
    [float('inf'),float('inf'),0,4,float('inf')],
    [float('inf'),float('inf'),2,0,3],
    [3,float('inf'),float('inf'),float('inf'),0]
]

其中g[i][j]表示i到j边的权重。

Floyd方法指的是如果要从N个结点中找一条i,j两点之间的最短路径,首先对比两点之间的距离与经过剩余N-2个结点中任意一个结点k1的距离:

g[i][j]=min(g[i][j],g[i][k1]+g[k1][j])

即从i到j中途经过点k1的距离与g[i][j]进行对比,选取较小的值作为经过中途经过一个点的最短路径。此处的i,j代表任意两点,将图中任意两点做以上步骤后可以得到一个新的g,这个g的g[i][j]意义为经过点k1后i到j的最短路径。

接下来计算中途经过k1和k2两个点时的情况,由于已经有了经过一个点时的结果,就可以在此基础上计算经过两个点时的最短路径。经过两个点时我们比较的是以下路径中的最小值:

g[i][j]
g[i][k1] + g[k1][j]
g[i][k2] + g[k2][j]
g[i][k1] + g[k1][k2] + g[k2][j]
g[i][k2] + g[k2][k1] + g[k1][j]

由于我们有了以下经过第一个点k1时的结论:

g[i][j]  = min(g[i][j] 或g[i][k1]  + g[k1][j])   ···········1
g[i][k2] = min(g[i][k2]或g[i][k1]  + g[k1][k2])  ···········2 
g[k2][j] = min(g[k2][j]或g[k2][k1] + g[k1][j])   ···········3

经过两个点时:

g[i][j] = min(g[i][j]或g[i][k2] + g[k2][j])
由1、2、3得:
g[i][j] = min(g[i][j]
              g[i][k1] + g[k1][j]
              g[i][k2] + g[k2][j]
              g[i][k1]  + g[k1][k2] + g[k2][j]
              g[i][k2] + g[k2][k1] + g[k1][j])

因此我们得到一般性规律,找图中两点i,j的最短路径时,可先考虑两点加任一点k1,找出图中任意两点经过点k1的最短路径并生成经过k1后的图的最短路径矩阵。之后引入除i,j,k1点外的任一点k2,由于在经过k1的最短路径矩阵的基础上计算经过两点的最短路径,可以直接重复第一步的过程。

完整Python代码如下:

graph = [
    [0,1,float('inf'),1,5],
    [9,0,3,2,float('inf')],
    [float('inf'),float('inf'),0,4,float('inf')],
    [float('inf'),float('inf'),2,0,3],
    [3,float('inf'),float('inf'),float('inf'),0]
]
n = len(graph)

for k in range(n):            //经过的每个点
    for i in range(n):        
        for j in range(n):
            if graph[i][j] > graph[i][k] + graph[k][j]:  //判断点i,j经过第0到第k-1个点时的最短路径
                    graph[i][j] = graph[i][k] + graph[k][j]

print(graph)

其中核心代码只有五行三重循环,时间复杂度为n³,n为输入图的结点数。如果数据量很小或对时间要求不高时,可以使用此简单方法生成最短路径。

猜你喜欢

转载自blog.csdn.net/tus00000/article/details/82952635