python数据结构与算法——图的最短路径(Bellman-Ford算法)解决负权边

 # Bellman-Ford核心算法
# 对于一个包含n个顶点,m条边的图, 计算源点到任意点的最短距离
# 循环n-1轮,每轮对m条边进行一次松弛操作 # 定理:
# 在一个含有n个顶点的图中,任意两点之间的最短路径最多包含n-1条边
# 最短路径肯定是一个不包含回路的简单路径(回路包括正权回路与负权回路)
# 1. 如果最短路径中包含正权回路,则去掉这个回路,一定可以得到更短的路径
# 2. 如果最短路径中包含负权回路,则每多走一次这个回路,路径更短,则不存在最短路径
# 因此最短路径肯定是一个不包含回路的简单路径,即最多包含n-1条边,所以进行n-1次松弛即可 G = {1:{1:0, 2:-3, 5:5},
2:{2:0, 3:2},
3:{3:0, 4:3},
4:{4:0, 5:2},
5:{5:0}} def getEdges(G):
""" 输入图G,返回其边与端点的列表 """
v1 = [] # 出发点
v2 = [] # 对应的相邻到达点
w = [] # 顶点v1到顶点v2的边的权值
for i in G:
for j in G[i]:
if G[i][j] != 0:
w.append(G[i][j])
v1.append(i)
v2.append(j)
return v1,v2,w class CycleError(Exception):
pass def Bellman_Ford(G, v0, INF=999):
v1,v2,w = getEdges(G) # 初始化源点与所有点之间的最短距离
dis = dict((k,INF) for k in G.keys())
dis[v0] = 0 # 核心算法
for k in range(len(G)-1): # 循环 n-1轮
check = 0 # 用于标记本轮松弛中dis是否发生更新
for i in range(len(w)): # 对每条边进行一次松弛操作
if dis[v1[i]] + w[i] < dis[v2[i]]:
dis[v2[i]] = dis[v1[i]] + w[i]
check = 1
if check == 0: break # 检测负权回路
# 如果在 n-1 次松弛之后,最短路径依然发生变化,则该图必然存在负权回路
flag = 0
for i in range(len(w)): # 对每条边再尝试进行一次松弛操作
if dis[v1[i]] + w[i] < dis[v2[i]]:
flag = 1
break
if flag == 1:
# raise CycleError()
return False
return dis v0 = 1
dis = Bellman_Ford(G, v0)
print dis.values()
上一篇:uva 558 - Wormholes(Bellman Ford判断负环)


下一篇:Bellman-Ford(可解决负权边)--时间复杂度优化