第24章《单源最短路径》:Bellman-Ford和Dijkstra算法,python实现

Bellman-Ford算法

Bellman-Ford算法解决的是一般情况下的单源最短路径问题,在这里,边的权重可以为负值。给定带权重的有向图 G = ( V , E ) G=(V,E) G=(V,E)和权重函数 w : E − R w: E-R w:ER,Bellman-Ford算法返回一个布尔值,以表明是否存在一个从源节点可以到达的权重为负值的环路,如果存在这样一个环路,算法将告诉我们不存在解决方案,如果没有这种环路存在,算法将给出最短路径和它们的权重。
Bellman-Ford算法实现步骤:

  • Step 1从带有权重的图开始
    在这里插入图片描述

  • Step 2:选择一个开始节点,并且给剩余其他节点路径距离赋值为无穷大
    在这里插入图片描述
    在这里插入图片描述

  • Step 3:访问每条边,进行松弛操作,更新节点距离
    在这里插入图片描述

  • Step 4:需要操作 V V V次,因为在最坏情况下,一个节点的路径距离可能需要调整V次

在这里插入图片描述

  • Step 5: 重复上面过程,最终从开始节点到每个节点的路径距离调整更新,获得最终结果
    在这里插入图片描述
    Bellman Ford算法的复杂度为 O ( V E ) O(VE) O(VE)
    python实现如下:
# -*-coding:utf8-*-
import sys

class Graph:
	def __init__(self, V):
		self.V = V
		self.graph = []
	# add edges
	def add_edge(self, s, d, w):
		self.graph.append([s, d, w])

	# print the solution
	def print_solution(self, dist):
		print(" Vertex Distance from Source")
		for i in range(self.V):
			print("{0}\t\t{1}".format(i, dist[i]))

	def bellman_ford(self, src):
		# step 1: fill the distance array and predecessor array
		dist = [float("Inf")] * self.V
		# Mark the source vertex
		dist[src] = 0
		
		# step 2 : relax edges |V|-1 times
		for _ in range(self.V - 1):
			for s, d, w in self.graph:
				if dist[s]!= float("Inf") and dist[s] + w < dist[d]:
					dist[d] = dist[s] + w
		# step 3: detect negative cycle
		for s, d, w in self.graph:
			if dist[s] != float("Inf") and dist[s] + w < dist[d]:
				print("Graph contains negative weight cycle")
				return 

		# No negative weight cycle found, print the distance
		self.print_solution(dist)
	

if __name__=='__main__':
	g = Graph(5)
	for s,d,w in [(0,1,4),(0,2,2),(1,2,3),(2,1,1),(1,3,2),(1,4,3),(2,4,5),(2,3,4),(4,3,-5)]:
		g.add_edge(s,d,w)
	g.bellman_ford(0)	

Dijkstra算法

Dijkstra算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值。注意与最小生成树的区别,最小生成树需要包含图中的所有节点,而Dijkstra算法是找出任意两个节点的最短路径。
Dijkstra算法的实现步骤如下:

  • Step 1: 从一个带有权重的图开始
    在这里插入图片描述

  • Step 2: 选择一个开始节点,并且对其它节点路径设置为无穷大
    在这里插入图片描述

  • Step 3: 遍历每个节点,并且更新路径长度
    在这里插入图片描述

  • Step 4: 节点的路径长度小于新的路径长度,则不更新

在这里插入图片描述

  • Step 5: 以及遍历过的节点不再更新路径长度
    在这里插入图片描述

  • Step 6: 每一次迭代,选择没有遍历过的节点,并且选择路径最小的一个,所以下图节点5在节点7之前选择
    在这里插入图片描述

  • Step 7:重复上面步骤,直到所有节点都遍历
    在这里插入图片描述
    Dijkstra算法时间复杂度为 O ( E l o g V ) O(ElogV) O(ElogV)
    python实现如下:

# -*-coding:utf8 -*-
import sys

class Graph:
	def __init__(self, vertices, edgs):
		self.vertices= vertices
		self.edgs = edgs
		self.num_of_vertices = len(vertices[0])
		self.visited_and_distance = [[0,0]]

	def to_be_visited(self):
		v = -1
		for index in range(self.num_of_vertices):
			if self.visited_and_distance[index][0] == 0 and (v < 0 or self.visited_and_distance[index][1] <= self.visited_and_distance[v][1]):
				v = index
		return v

	def distance(self):
		for i in range(self.num_of_vertices-1):
			self.visited_and_distance.append([0, sys.maxsize])
		for vertex in range(self.num_of_vertices):
			# find next vertex to be visited
			to_visit = self.to_be_visited()
			for neighbor_index in range(self.num_of_vertices):
				if self.vertices[to_visit][neighbor_index] ==1 and self.visited_and_distance[neighbor_index][0] == 0:
					new_distance = self.visited_and_distance[to_visit][1] + edges[to_visit][neighbor_index]
					if self.visited_and_distance[neighbor_index][1] > new_distance:
						self.visited_and_distance[neighbor_index][1] = new_distance
				self.visited_and_distance[to_visit][0] = 1

if __name__=='__main__':
	vertices = [[0, 0, 1, 1, 0, 0, 0],
				[0, 0, 1, 0, 0, 1, 0],
            [1, 1, 0, 1, 1, 0, 0],
            [1, 0, 1, 0, 0, 0, 1],
            [0, 0, 1, 0, 0, 1, 0],
            [0, 1, 0, 0, 1, 0, 1],
            [0, 0, 0, 1, 0, 1, 0]]

	edges = [[0, 0, 1, 2, 0, 0, 0],
         [0, 0, 2, 0, 0, 3, 0],
         [1, 2, 0, 1, 3, 0, 0],
         [2, 0, 1, 0, 0, 0, 1],
         [0, 0, 3, 0, 0, 2, 0],
         [0, 3, 0, 0, 2, 0, 1],
         [0, 0, 0, 1, 0, 1, 0]]

	graph = Graph(vertices, edges)
	graph.distance()
	i = 0
	for distance in graph.visited_and_distance:
		print("Distance of ", chr(ord('a')+i), "from source vertex: ", distance[1])
		i+=1	

猜你喜欢

转载自blog.csdn.net/BGoodHabit/article/details/107032961