赞
踩
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]
表示点A
和G
之间的最短距离,而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')
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。