图的最短路径算法
声明:图源 https://blog.csdn.net/qq_35644234/article/details/60875818
算法代码源 https://www.jianshu.com/p/f910ce1fe7b1
本文主要是代码理解的注解以及调试。。。哇,我觉得代码写的清晰的人真的很厉害啊
转自:作者:廖少少
链接:https://www.jianshu.com/p/f910ce1fe7b1
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
import copy
#定义无穷值
inf=float("inf")
def Floyd(G):
n=len(G)
path=copy.deepcopy(G)
#vi源点,vj目的点,vk作为中间点
for k in range(0,n):
for i in range(0,n):
for j in range(0,n):
print("Comparing path[%s][%s] and {path[%s][%s]+path[%s][%s]}"%(i,j,i,k,k,j))
print("Former path[%s][%s]=%s"%(i,j,path[i][j]))
path[i][j]=min(path[i][k]+path[k][j],path[i][j])
print("Present path[%s][%s]=%s"%(i,j,path[i][j]))
return path
if __name__ == "__main__":
G=[
[inf,12,inf,inf,inf,16,14],
[12,inf,10,inf,inf,7,inf],
[inf,10,inf,3,5,6,inf],
[inf,inf,3,inf,4,inf,inf],
[inf,inf,5,4,inf,2,8],
[16,7,6,inf,2,inf,9],
[14,inf,inf,inf,8,9,inf]
]
print("---------------Floyd----------------")
path=Floyd(G)
print("Graph=")
for i in range(0,len(G)):
print((path[i]))
输出:
Graph=
[24, 12, 22, 22, 18, 16, 14]
[12, 14, 10, 13, 9, 7, 16]
[22, 10, 6, 3, 5, 6, 13]
[22, 13, 3, 6, 4, 6, 12]
[18, 9, 5, 4, 4, 2, 8]
[16, 7, 6, 6, 2, 4, 9]
[14, 16, 13, 12, 8, 9, 16]
Floyd 算法适用于 APSP(All Pairs Shortest Paths,多源最短路径),是一种动态规划算法,稠密图效果最佳,边权可正可负。此算法简单有效,由于三重循环结构紧凑,对于稠密图,效率要高于执行 | V | 次 Dijkstra 算法,也要高于执行 | V | 次 SPFA 算法。
找最短路径以及全局最短路径[加入中间点k]
import copy
#定义无穷值
inf=float("inf")
def Floyd(G):
n=len(G)
path=copy.deepcopy(G)
#vi源点,vj目的点,vk作为中间点
for k in range(0,n):
for i in range(0,n):
for j in range(0,n):
print("Comparing path[%s][%s] and {path[%s][%s]+path[%s][%s]}"%(i,j,i,k,k,j))
print("Former path[%s][%s]=%s"%(i,j,path[i][j]))
path[i][j]=min(path[i][k]+path[k][j],path[i][j])
print("Present path[%s][%s]=%s"%(i,j,path[i][j]))
return path
#递归回溯找最短路径
def back_path(path,i,j,shortestpath):
#path[i][j]的结果就是中转点
print("path[%s][%s]="%(i,j),path[i][j])
#如果两个顶点邻接path[i][j]=-1
if -1 != path[i][j]:
shortestpath=back_path(path,i,path[i][j],shortestpath)
shortestpath=back_path(path,path[i][j],j,shortestpath)
if j not in shortestpath:
shortestpath.append(j)
return shortestpath
#找两点之间最短路径
def getShortestPath(graph,path,i,j):
shortestPath=[]
if graph[i][j] == float("inf") or i == j :
print("顶点 %s 不能到达 %s"%(i,j))
return shortestPath
elif path[i][j] == -1:
shortestPath.append(i)
shortestPath.append(j)
else:
shortestPath.append(i)
shortestPath=back_path(path,i,j,shortestPath)
print("顶点%s 到 顶点%s 的路径为:"%(i,j),shortestPath)
return shortestPath
#找全局最短路径
def getAllShortestPath(graph,path):
print("----------全局最短路径-----------")
ShortestPath_dict = {}
for i in range(len(graph)):
ShortestPath_dict[i] = {}
for j in range(len(graph)):
print("生成顶点%s到顶点%s的最短路径"%(i,j))
if i != j:
shortestPath=getShortestPath(graph,path,i,j)
ShortestPath_dict[i][j] = shortestPath
return ShortestPath_dict
if __name__ == "__main__":
graph=[
[inf,12,inf,inf,inf,16,14],
[12,inf,10,inf,inf,7,inf],
[inf,10,inf,3,5,6,inf],
[inf,inf,3,inf,4,inf,inf],
[inf,inf,5,4,inf,2,8],
[16,7,6,inf,2,inf,9],
[14,inf,inf,inf,8,9,inf]
]
#更新图
# print("---------------Floyd----------------")
# path=Floyd(G)
# print("Graph=")
# for i in range(0,len(G)):
# print((path[i]))
path=[]
for i in range(len(graph)):
path.append([])
for j in range(len(graph)):
#邻接
path[i].append(-1)
print("original graph:\n",graph)
#加入中间点实现Floyd算法
for k in range(len(graph)):
for i in range(len(graph)):
for j in range(len(graph)):
if graph[i][k] + graph[k][j] <graph[i][j]:
graph[i][j] = graph[i][k] + graph[k][j]
#维护最短路径列表
path[i][j] =k
print("Shortestpath Graph:\n",graph)
print("Path:\n",path)
#获取全局最短路径
print("ShortestPath_dict=\n",getAllShortestPath(graph,path))
写的太好了!!
输出
original graph:
[ [inf, 12, inf, inf, inf, 16, 14],
[12, inf, 10, inf, inf, 7, inf],
[inf, 10, inf, 3, 5, 6, inf],
[inf, inf, 3, inf, 4, inf, inf],
[inf, inf, 5, 4, inf, 2, 8],
[16, 7, 6, inf, 2, inf, 9],
[14, inf, inf, inf, 8, 9, inf]]
Shortestpath Graph:
[ [24, 12, 22, 22, 18, 16, 14],
[12, 14, 10, 13, 9, 7, 16],
[22, 10, 6, 3, 5, 6, 13],
[22, 13, 3, 6, 4, 6, 12],
[18, 9, 5, 4, 4, 2, 8],
[16, 7, 6, 6, 2, 4, 9],
[14, 16, 13, 12, 8, 9, 16]]
Path:
[ [1, -1, 1, 5, 5, -1, -1],
[-1, 5, -1, 2, 5, -1, 5],
[1, -1, 3, -1, -1, -1, 4],
[5, 2, -1, 2, -1, 4, 4],
[5, 5, -1, -1, 5, -1, -1],
[-1, -1, -1, 4, -1, 4, -1],
[-1, 5, 4, 4, -1, -1, 4]]
ShortestPath_dict=
{ 0: {1: [0, 1], 2: [0, 1, 2], 3: [0, 5, 4, 3], 4: [0, 5, 4], 5: [0, 5], 6: [0, 6]},
1: {0: [1, 0], 2: [1, 2], 3: [1, 2, 3], 4: [1, 5, 4], 5: [1, 5], 6: [1, 5, 6]},
2: {0: [2, 1, 0], 1: [2, 1], 3: [2, 3], 4: [2, 4], 5: [2, 5], 6: [2, 4, 6]},
3: {0: [3, 4, 5, 0], 1: [3, 2, 1], 2: [3, 2], 4: [3, 4], 5: [3, 4, 5], 6: [3, 4, 6]},
4: {0: [4, 5, 0], 1: [4, 5, 1], 2: [4, 2], 3: [4, 3], 5: [4, 5], 6: [4, 6]},
5: {0: [5, 0], 1: [5, 1], 2: [5, 2], 3: [5, 4, 3], 4: [5, 4], 6: [5, 6]},
6: {0: [6, 0], 1: [6, 5, 1], 2: [6, 4, 2], 3: [6, 4, 3], 4: [6, 4], 5: [6, 5]}}
多源最短路径!!!任意两点
过程描述:
1.读原始图
2.加入中间点实现Floyd算法
得到最短路径图ShortestPath graph
3.尝试顶点0到顶点2的最短路径
为了避免重复,加入了 if 判断,直接过滤掉重复的顶点,因为最短路径不可能绕圈子。
Debug
因为自己每次写代码都是静态检查,所以想借用这个算法学习一下python的Debug过程,观察一下程序的运行: