Floyd算法分析

一、算法原理

Floyd-Warshall算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题。Floyd算法的根本原理是动态规划。

算法描述

开始:对于每一对顶点 v v v v ′ v^′ v,从 v v v v ′ v^′ v图中不经过任何其他顶点,如果 v v v v ′ v^′ v存在边,那么长度就是该边的权,如果没边就设长度为无穷大。
k = 0:即对于每一对顶点 v v v v ′ v^′ v,途径顶点的下标不大于k,实际上这里只能经过 v 0 v_0 v0,该路径可分为两段,即< v v v v 0 v_0 v0 > 和< v 0 v_0 v0 v ′ v^′ v>这一长度就是两段路径的长度之和,比较这一新路径和之前的路径< v v v v ′ v^′ v>,就可以确定 v v v v ′ v^′ v途经下标不大于k的最短路径。

k = 1:同理,该路径可拆成< v v v, … , v 1 v_1 v1 > 和< v 1 v_1 v1,… v ′ v^′ v >两段,这两段的长度在k = 0的时候就确定了,再比较新路径和前面已知的路径
< v v v v ′ v^′ v>就可以确定途经下标不大于k 的最短路径,此时k = 1。
重复以上步骤,直到k = n − 1为止,此时已经确定了从 v v v v ′ v^′ v所有可能的最短路径。

二、代码实现

以下代码来源于该博客最短路:Floyd算法(Python实现)
在这里插入图片描述
基于上图,可以用邻接字典表表示,Floyd算法需要将其转为邻接矩阵形式,以下代码实现该功能

graph = {'A': [(7, 'A', 'B'), (5, 'A', 'D')], 
         'B': [(7, 'B', 'A'), (8, 'B', 'C'), (9, 'B', 'D'), (7, 'B', 'E')], 
         'C': [(8, 'C', 'B'), (5, 'C', 'E')],
         'D': [(5, 'D', 'A'), (9, 'D', 'B'), (15, 'D', 'E'), (6, 'D', 'F')], 
         'E': [(7, 'E', 'B'), (5, 'E', 'C'), (15, 'E', 'D'), (8, 'E', 'F'), (9, 'E', 'G')], 
         'F': [(6, 'F', 'D'), (8, 'F', 'E'), (11, 'F', 'G')],
         'G': [(9, 'G', 'E'), (11, 'G', 'F')]
        }
def graph2adjacent_matrix(graph):
    vnum = len(graph)
    dict = {'A':0,'B':1,'C':2,'D':3,'E':4,'F':5,'G':6}
    adjacent_matrix = [[0 if row==col else float('inf') for col in range(vnum)] for row in range(vnum)]
    vertices = graph.keys()
    for vertex in vertices:
        for edge in graph[vertex]:
            w,u,v = edge
            adjacent_matrix[dict.get(u)][dict.get(v)]=w
    return adjacent_matrix

其中,第12行为创建初始邻接矩阵,相同点之间的距离为0,其余距离皆设为无穷大。
第14行至第18行,将有连接的两点间的权值填充到邻接矩阵中,并返回邻接矩阵。

接下来就运用Floyd算法:

def floyd(adjacent_matrix):
    vnum = len(adjacent_matrix)
    a = [[adjacent_matrix[row][col] for col in range(vnum)] for row in range(vnum)]
    nvertex = [[-1 if adjacent_matrix[row][col]==float('inf') else col for col in range(vnum)] for row in range(vnum)]
    # print(adjacent_matrix)
    for k in range(vnum):
        for i in range(vnum):
            for j in range(vnum):
                if a[i][j]>a[i][k]+a[k][j]:
                    a[i][j]=a[i][k]+a[k][j] 
                    nvertex[i][j] = nvertex[i][k]
    return nvertex, a

adjacent_matrix = graph2adjacent_matrix(graph)
nvertex, a = floyd(adjacent_matrix)
### 打印原邻接矩阵 ###
for i in range(len(adjacent_matrix)):
    for j in range(len(adjacent_matrix[0])):
        print(adjacent_matrix[i][j],end="\t")
    print()#打印一行后换行
### 打印经过的顶点 ###
print()
for i in range(len(nvertex)):
    for j in range(len(nvertex[0])):
        print(nvertex[i][j],end="\t")
    print()#打印一行后换行
### 打印彼此之间的最短距离 ###
print()
for i in range(len(a)):
    for j in range(len(a[0])):
        print(a[i][j],end="\t")
    print()#打印一行后换行

其中,第1行至第12行为Floyd算法原理的实现。a表示最短距离矩阵,即a[0][6]表示点AG之间的最短距离,而nvertex矩阵中的nvertex[i][j]表示 v i v_i vi v j v_j vj之间最短路中 v i v_i vi的后继顶点,根据该矩阵可以之后任意最短路中间经过的顶点。例如下方该矩阵:在这里插入图片描述
我们找出A到G最短路中间经过的顶点,A对应0,G对应6,我们找到nvertex[0][6]=3,也就是A到G的最短路A的后继是D,即A->D->…->G,我们在找D和G,即nvertex[3][6]=5,即D的后继是F,然后找nvertex[5][6]=6,F的后继是G,最后A到G的最短路就是A->D->F->G。

以上来源于博客最短路:Floyd算法(Python实现)但该博客中的代码仅实现了打印两点间最短的距离,未输出最短路径,所以作者设想加入以下代码(由于本人编程小白-_-,实现该功能输出时存在一些问题,路径是倒着的,待改进):

#这里要加import 不然会报错 函数有调用自身
import sys

def print_path(i, j):
    if j != nvertex[i][j]:
        print_path(nvertex[i][j], j)
    print('<--'+ str(i),end='')

#打印最短路径
print('\nPath:')
for i in range(len(nvertex)):
    for j in range(len(nvertex[0])):
        print('Path({}-->{}): '.format(i, j), end='')
        print_path(i, j)
        print(' cost:', adjacent_matrix[i][j])

输出结果如下:

Path:
Path(0–>0): <–0 cost: 0
Path(0–>1): <–0 cost: 7
Path(0–>2): <–1<–0 cost: inf
Path(0–>3): <–0 cost: 5
Path(0–>4): <–1<–0 cost: inf
Path(0–>5): <–3<–0 cost: inf
Path(0–>6): <–5<–3<–0 cost: inf
Path(1–>0): <–1 cost: 7
Path(1–>1): <–1 cost: 0
Path(1–>2): <–1 cost: 8
Path(1–>3): <–1 cost: 9
Path(1–>4): <–1 cost: 7
Path(1–>5): <–3<–1 cost: inf
Path(1–>6): <–4<–1 cost: inf
Path(2–>0): <–1<–2 cost: inf
Path(2–>1): <–2 cost: 8
Path(2–>2): <–2 cost: 0
Path(2–>3): <–1<–2 cost: inf
Path(2–>4): <–2 cost: 5
Path(2–>5): <–4<–2 cost: inf
Path(2–>6): <–4<–2 cost: inf
Path(3–>0): <–3 cost: 5
Path(3–>1): <–3 cost: 9
Path(3–>2): <–1<–3 cost: inf
Path(3–>3): <–3 cost: 0
Path(3–>4): <–5<–3 cost: 15
Path(3–>5): <–3 cost: 6
Path(3–>6): <–5<–3 cost: inf
Path(4–>0): <–1<–4 cost: inf
Path(4–>1): <–4 cost: 7
Path(4–>2): <–4 cost: 5
Path(4–>3): <–5<–4 cost: 15
Path(4–>4): <–4 cost: 0
Path(4–>5): <–4 cost: 8
Path(4–>6): <–4 cost: 9
Path(5–>0): <–3<–5 cost: inf
Path(5–>1): <–3<–5 cost: inf
Path(5–>2): <–4<–5 cost: inf
Path(5–>3): <–5 cost: 6
Path(5–>4): <–5 cost: 8
Path(5–>5): <–5 cost: 0
Path(5–>6): <–5 cost: 11
Path(6–>0): <–3<–5<–6 cost: inf
Path(6–>1): <–4<–6 cost: inf
Path(6–>2): <–4<–6 cost: inf
Path(6–>3): <–5<–6 cost: inf
Path(6–>4): <–6 cost: 9
Path(6–>5): <–6 cost: 11
Path(6–>6): <–6 cost: 0

备注

这里给出代码中一个表达方式的解释,由于本人是编程小白,这是第二次看到该表达方法,觉得可以记录以下:

adjacent_matrix = [[0 if row==col else float('inf') for col in range(vnum)] for row in range(vnum)]

该代码等价于

for row in range(vnum):
	for col in range(vnum):
		if row == col:
			adjacent_matrix[row][col] = 0
		else:
			adjacent_matrix[row][col] = float('inf')

参考

最短路:Floyd算法(Python实现)

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值