第24章「単一ソース最短経路」:ベルマンフォード法とダイクストラ法のアルゴリズム、Pythonの実装

ベルマンフォードアルゴリズム

ベルマンフォードアルゴリズムは、一般に、エッジの重みが負になる可能性がある単一ソースの最短経路問題を解決します。重み付き有向グラフが与えられた場合G =(V、E)G =(V、E)G=V E および重み関数w:E − R w:ERwER、ベルマンフォードアルゴリズムはブール値を返し、ソースノードから到達できる負の重みを持つループがあるかどうかを示します。そのようなループがある場合、アルゴリズムは解決策がないことを通知します。そのようなループはありませんループが存在し、アルゴリズムは最短パスとその重みを与えます。
ベルマンフォードアルゴリズムの実装手順:

  • ステップ1重み付きのグラフから始めます
    ここに画像の説明を挿入します

  • ステップ2:開始ノードを選択し、残りのノードのパス距離を無限大に割り当てます
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します

  • ステップ3:各エッジにアクセスし、緩和操作を実行して、ノード距離を更新します
    ここに画像の説明を挿入します

  • ステップ4:VVを操作する必要があるVの時間は、最悪の場合、ノードの経路距離は、V時間を調整する必要があるかもしれないので

ここに画像の説明を挿入します

  • ステップ5:上記のプロセスを繰り返し、最後に開始ノードから各ノードまでのパス距離を調整および更新して、最終結果を取得し
    ここに画像の説明を挿入します
    ます。ベルマンフォードアルゴリズムの複雑さはO(VE)O(VE)です。O V E
    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)	

ダイクストラアルゴリズム

ダイクストラアルゴリズムは、重み付きの有向グラフ上の単一ソース最短経路問題を解決します。アルゴリズムでは、すべてのエッジの重みが負でない必要があります。最小スパニングツリーとの違いに注意してください。最小スパニングツリーにはグラフ内のすべてのノードが含まれている必要がありますが、ダイクストラアルゴリズムは任意の2つのノード間の最短パスを見つけることです。
ダイクストラのアルゴリズムの実装手順は次のとおりです。

  • ステップ1:重み付きのグラフから始めます
    ここに画像の説明を挿入します

  • ステップ2:開始ノードを選択し、他のノードのパスを無限大に設定します
    ここに画像の説明を挿入します

  • ステップ3:各ノードをトラバースし、パスの長さを更新します
    ここに画像の説明を挿入します

  • ステップ4:ノードのパス長が新しいパス長より短い場合、ノードは更新されません

ここに画像の説明を挿入します

  • ステップ5:トラバースされたノードはパスの長さを更新しなくなりました
    ここに画像の説明を挿入します

  • ステップ6:各反復で、トラバースされていないノードを選択し、パスが最小のノードを選択します。これにより、次の図のノード5がノード7の前に選択されます。
    ここに画像の説明を挿入します

  • ステップ7:すべてのノードが
    ここに画像の説明を挿入します
    ダイクストラアルゴリズムを通過するまで上記のステップを繰り返します。時間計算量はO(E log V)O(ElogV)です。O E l o g V
    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