对于求图的最短路径问题,如果使用迪杰斯特拉算法,也可以算是一个较为常见的方法,但是对于迪杰斯特拉算法解决最短路径问题的时候,会存在一个问题,那就是所有边所对应的距离都必须是正数,而如果在存在负数的边的时候,迪杰斯特拉算法就会存在问题,而对于存在负数的这种情况,可以使用贝尔曼福德算法来解决图中任意两点的最短路径问题,即使某条路径中所对应的长度是负数的时候。
贝尔曼福德算法的基本思想是,先把起始节点到其他所有节点的距离设置为无穷大,然后执行两个循环,外层循环的次数与图中的节点数相同,内层循环的次数与图中边的数量相同,在内层循环中,没变里到一条边(u,v)的时候,算法判断起始节点到节点u的距离加上边(u,v)的长度是否小于起始节点到节点v的距离,如果是的,那就修改起始节点到节点v的长度距离。
如果假设给定的图如下图所示:
添加图片注释,不超过 140 字(可选)
除了给定节点对应标号之外,每个节点中还给出了起始节点到该节点的最短距离,一开始除了起始节点到它自己的距离为0之外,起始节点到其他节点的距离都初始化为无穷大,由于图中总共有6个节点和9条边,因此外层循环有6次,内层循环有9次。
添加图片注释,不超过 140 字(可选)
添加图片注释,不超过 140 字(可选)
在使用python实现贝尔曼福德算法的代码如下:
def bellman_ford(s, vertex_list, edges):
distance = {}
for v in vertex_list: #将起始节点与其他节点的距离设置为无穷大
if v == s:
distance[(s, v)] = 0
else:
distance[(s, v)] = sys.maxsize
for i in range(len(vertex_list)): #外层循环对应图中点的数量
for edge in edges.keys(): #内层循环对应图中边的数量
u = edge[0]
v = edge[1]
if distance[(s, u)] < sys.maxsize and distance[(s, u)] + edges[edge] < distance[(s, v)]:
distance[(s, v)] = distance[(s, u)] + edges[edge]
print("from {0} to {1} then to {2} can be shorter with distance {3}".format(s, u, v, distance[(s, v)]))
for edge in edges.keys(): #检测是否有负环生成
u = edge[0]
v = edge[1]
if distance[(s, v)] > distance[(s, u)] + edges[edge]:
return None
return distance
distances = bellman_ford('A', vertex_list, edges)
for d in distances.keys():
print("the shortest path from A to {0} is {1}".format(d[1], distances[d]))