Floyd-Warshall算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题。Floyd算法的根本原理是动态规划。
算法描述
开始:对于每一对顶点 v v v和 v ′ v' v′,从 v v v到 v ′ v' v′图中不经过任何其他顶点,如果 v v v到 v ′ v' v′存在边,那么长度就是该边的权,如果没边就设长度为无穷大
k = 0 k=0 k=0:即对于每一对顶点v和v’,途径顶点的下标不大于 k k k,实际上这里只能经过 v 0 v_0 v0,该路径可分为两段,即 < v , v 0 > <v,v_0> <v,v0>和 < v 0 , v ′ > <v_0,v'> <v0,v′>,这一长度就是两段路径的长度之和,比较这一新路径和之前的路径 < v , v ′ > <v,v'> <v,v′>,就可以确定 v v v到 v ′ v' v′途经下标不大于k的最短路径
k
=
1
k=1
k=1:同理,该路径可拆成
<
v
,
…
,
v
1
>
<v,… ,v_1>
<v,…,v1>和
<
v
1
,
…
,
v
′
>
<v_1,…,v'>
<v1,…,v′>两段,这两段的长度在
k
=
0
k=0
k=0的时候就确定了,再比较新路径和前面已知的路径
<
v
,
v
′
>
<v,v'>
<v,v′>就可以确定途经下标不大于
k
k
k的最短路径,此时
k
=
1
k=1
k=1
重复以上步骤,直到
k
=
n
−
1
k=n-1
k=n−1为止,此时已经确定了从
v
v
v到
v
′
v'
v′所有可能的最短路径
代码实现
对于上图,可以用邻接字典表表示,然后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
然后运用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()#打印一行后换行
其中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。