ダイクストラ法とは
2頂点間の最短距離を求める。
重みがマイナスだと使えない。
計算量
O(頂点数2) (オリジナルの場合)
O((頂点数+辺の数)* log頂点数) (優先度付きキューの場合)
※厳密な計算量はWikipediaを参考にすること。
処理概要
- 全ての頂点に、始点からの距離無限大を仮で書き込む。(初期化)
- 始点に、始点からの距離0を書き込む。(初期化)
- 次に行ける頂点に対して、始点からの距離を計算、現在書き込まれている距離より短ければ更新する。
- 始点からの距離が最も小さい&未訪問の頂点を選び、その頂点に行く。
- 未訪問頂点がまだあれば、3~4を繰り返す。
- すべての頂点が訪問済になったら終了。
ソースコード
N=6 visited=[False]*N #始点からの距離。初めは全頂点に無限値にする startFromDistance=[math.inf]*N #(頂点番号,重み)のタプルを持つグラフ G=[[(1,1),(2,5)] ,[(0,1),(2,4),(3,2)] ,[(0,5),(1,2),(4,2)] ,[(2,3),(5,3)] ,[(2,1),(5,4)] ,[]] def dijkstra(G, vertex): heap=[(0,0)]#重み、頂点番号(優先度付きキュー。最も重みの軽い頂点から優先で取り出す) startFromDistance[0] = 0 while len(heap) > 0: distance, now = heapq.heappop(heap) if visited[now]: continue visited[now] = True for next, weight in G[now]: if visited[next]: continue # nowから到達可能な頂点の距離更新 newDistance = startFromDistance[now] + weight if newDistance < startFromDistance[next]: startFromDistance[next] = newDistance #次の行き先候補を格納 heapq.heappush(heap, (newDistance, next)) return startFromDistance print(dijkstra(G, 0)) #[0, 1, 5, 3, 7, 6]
定式化
最短経路問題を定式化する。
頂点集合(V)={0 1 2 3 4 5}
辺集合(Ei,j)={(0,1), (0,2),(1,0),(1,2),(1,3),(2,0),(2,1),(2,4),(3,2),(3,5),(4,2),(4,5)}
重み集合(Wi,j)=W01=1, W02=5, W10=1, W12=2, W13=2, W20=5, W21=4, W24=2, W32=3,W35=3, W42=1, W45=4
決定変数(Xi,j)
「辺(i, j) ∈ E」 が最短路に含まれる場合、Xi,j=1
「辺(i, j) ∈ E 」が最短路に含まれない場合、Xi,j=0
移動距離Zは
始点sの出入
終点tの出入
始点と終点以外の地点の出入り
Xijは0か1をとる Xij ∈ {1,0} for (i, j) ∈ E
決定変数が0か1をとる問題を整数最適化問題と呼ぶ。
定式化例題
画像のグラフを最短経路問題として定式化する。
・目的変数
Z(移動距離)= X01 + 5X02 + X10 + 2X12 + 2X13 + 5X20 + 4X21 + 2X24 + 3X32 + 3X35 + 4X45
・制約条件
(X01 + X02) -(X10+X20) = 1 始点sの出入り
(X42 + X45) - X24 = -1 終点tの出入り
(X10 + X12+X13) - (X01+X21) = 0 頂点1の出入り
(X20+X21+X24) - (X02 + X12 + X32 + X42) = 0 頂点2の出入り
(X32 + X35) - X13 = 0 頂点3の出入り
-(X35 + X45) = 0 頂点5の出入り
XIJ >= 0 for (i, j) ∈ E Xijは0か1をとる