1 最短経路問題の定式化
重み付きグラフ G = ( V , E , w ) とは,グラフ G = ( V , E ) と重み関数 w : E → R の組である.経路 P = v 0 v 1 ⋯ v k に対して, P の 重み (または長さ)を w ( P ) = i = 0 ∑ k − 1 w ( v i , v i + 1 )
と定める.
頂点 s から t への経路全体を P ( s , t ) とする. 最短距離 を δ ( s , t ) = ⎩ ⎨ ⎧ min P ∈ P ( s , t ) w ( P ) − ∞ ∞ P ( s , t ) = ∅ かつ負閉路を経由しない場合 s から t に到達可能な負閉路が存在する場合 P ( s , t ) = ∅ の場合
と定める. w ( P ) = δ ( s , t ) を満たす経路 P を 最短経路 (shortest path)という.
2 BFS最短路:重みなしの場合
すべての辺の重みが 1 のとき,BFS(幅優先探索)が最短距離を正しく計算する.
重みなしグラフ G = ( V , E ) において,始点 s から BFS を実行し d [ v ] を v が発見された層とする.このとき任意の v ∈ V に対して d [ v ] = δ ( s , v ) が成り立つ.
δ ( s , v ) = k とし,帰納法で示す. k = 0 のとき v = s であり d [ s ] = 0 なので成立. k ≥ 1 とし, δ ( s , v ) ≤ k − 1 のすべての頂点で成立を仮定する. s から v への最短路 s = u 0 , u 1 , … , u k = v を取る. δ ( s , u k − 1 ) = k − 1 であるから帰納法の仮定より d [ u k − 1 ] = k − 1 である.BFS は u k − 1 を処理する際に v を(未訪問なら)キューに追加するので d [ v ] ≤ k となる.一方 d [ v ] < k であれば δ ( s , v ) < k となって矛盾する(BFS は各辺をちょうど 1 ステップで辿るため, d [ v ] 以下の距離の経路が存在することになる).よって d [ v ] = k . □
BFS の計算量は O ( ∣ V ∣ + ∣ E ∣ ) である.
Input:
グラフ G = ( V , E ) ,始点 s Output:
各頂点の最短距離 d [ v ] for all v ∈ V
d [ v ] ← + ∞
end for
d [ s ] ← 0
キュー Q ← ∅
Enqueue (Q , s )
while Q = ∅
u ← Dequeue ( Q )
for all v ∈ Adj ( u )
if d [ v ] = + ∞
d [ v ] ← d [ u ] + 1
Enqueue (Q , v )
end if
end for
end while
return d
3 Dijkstra のアルゴリズム
辺の重みが 非負 の場合に,単一始点最短路を効率的に求める手法が Dijkstra のアルゴリズムである.
アルゴリズムの骨子は次の通りである:確定済み集合 S を管理し, S に属さない頂点のうち暫定距離 d [ v ] が最小のものを選んで S に追加し,その頂点から出る辺で 緩和 (relaxation)を行う.
辺 ( u , v ) に対する 緩和 とは, d [ v ] > d [ u ] + w ( u , v ) ならば d [ v ] ← d [ u ] + w ( u , v ) と更新する操作をいう.
辺の重みがすべて非負であるグラフにおいて,Dijkstra のアルゴリズムは各頂点 v に対して d [ v ] = δ ( s , v ) を正しく計算する.
S に追加される頂点 u に対して d [ u ] = δ ( s , u ) であることを, S に追加される順に帰納法で示す.
基底: s が最初に追加され d [ s ] = 0 = δ ( s , s ) である.
帰納段階: S に新たに追加される頂点を u とする. d [ u ] > δ ( s , u ) と仮定して矛盾を導く. s から u への最短路 P を取り, P 上で S を初めて出る辺 ( x , y ) ( x ∈ S , y ∈ / S )を考える.帰納法の仮定より d [ x ] = δ ( s , x ) である. x を S に追加した時点で辺 ( x , y ) を緩和しているので, d [ y ] ≤ d [ x ] + w ( x , y ) = δ ( s , x ) + w ( x , y ) = δ ( s , y ) .
一方, w ≥ 0 より δ ( s , y ) ≤ δ ( s , u ) である( y は P 上で u 以前).よって d [ y ] ≤ δ ( s , u ) < d [ u ] であるが, u は S 外で d が最小の頂点として選ばれたので d [ u ] ≤ d [ y ] であり矛盾. □
Input:
グラフ G = ( V , E ) ,非負重み w ,始点 s Output:
各頂点の最短距離 d [ v ] for all v ∈ V
d [ v ] ← + ∞
end for
d [ s ] ← 0
優先度付きキュー Q に全頂点を d 値で挿入
while Q = ∅
u ← ExtractMin ( Q )
for all ( u , v ) ∈ E
if d [ u ] + w ( u , v ) < d [ v ]
d [ v ] ← d [ u ] + w ( u , v )
DecreaseKey (Q , v , d [ v ] )
end if
end for
end while
return d
4 Bellman-Ford アルゴリズム
辺の重みに負が含まれる場合,Dijkstra は正しく動作しない.Bellman-Ford アルゴリズムは負の辺重みを許容し,さらに負閉路の検出も可能である.
アルゴリズムはすべての辺に対する緩和を ∣ V ∣ − 1 回繰り返す.
負閉路が存在しないグラフにおいて, ∣ V ∣ − 1 回の反復後,すべての頂点 v に対して d [ v ] = δ ( s , v ) が成り立つ.
最短路は(負閉路がなければ)高々 ∣ V ∣ − 1 本の辺からなる. s から v への最短路を s = v 0 , v 1 , … , v k = v ( k ≤ ∣ V ∣ − 1 )とする. i 回目の反復後に d [ v i ] = δ ( s , v i ) が成り立つことを i に関する帰納法で示す. i = 0 は d [ s ] = 0 で成立. i ≥ 1 のとき,帰納法の仮定より ( i − 1 ) 回目の反復後に d [ v i − 1 ] = δ ( s , v i − 1 ) である. i 回目の反復で辺 ( v i − 1 , v i ) を緩和するので, d [ v i ] ≤ d [ v i − 1 ] + w ( v i − 1 , v i ) = δ ( s , v i − 1 ) + w ( v i − 1 , v i ) = δ ( s , v i ) .
d [ v i ] ≥ δ ( s , v i ) は緩和の性質から常に成り立つので等号が成立する. □
Bellman-Ford の ∣ V ∣ − 1 回の反復後にさらに 1 回すべての辺を緩和して, d [ v ] が更新される頂点 v が存在すれば, s から到達可能な負閉路が存在する.
負閉路がなければ ∣ V ∣ − 1 回目で全頂点の d 値が確定し,追加の緩和で更新は起きない.対偶より,更新が起きれば負閉路が存在する. □
Bellman-Ford の計算量は O ( ∣ V ∣ ⋅ ∣ E ∣ ) である.
Input:
有向グラフ G = ( V , A ) ,重み w ,始点 s Output:
各頂点の最短距離 d [ v ] ,負閉路の有無 for all v ∈ V
d [ v ] ← + ∞
end for
d [ s ] ← 0
for i = 1 to ∣ V ∣ − 1
for all ( u , v ) ∈ A
if d [ u ] + w ( u , v ) < d [ v ]
d [ v ] ← d [ u ] + w ( u , v )
end if
end for
end for
for all ( u , v ) ∈ A
if d [ u ] + w ( u , v ) < d [ v ]
return 「負閉路が存在する」
end if
end for
return d
5 Warshall-Floyd アルゴリズム
全頂点対間の最短距離を動的計画法で求める手法が Warshall-Floyd アルゴリズムである.
V = { 1 , 2 , … , n } とし, d ( k ) ( i , j ) を中間頂点として { 1 , … , k } のみを使う i から j への最短距離とする.このとき d ( k ) ( i , j ) = min ( d ( k − 1 ) ( i , j ) , d ( k − 1 ) ( i , k ) + d ( k − 1 ) ( k , j ) )
が成り立ち, d ( n ) ( i , j ) = δ ( i , j ) である.
頂点 k を中間頂点として使わない最短路の重みは d ( k − 1 ) ( i , j ) に等しい.頂点 k を使う場合,最短路は i → ⋯ → k → ⋯ → j と分解でき(負閉路がなければ k は最短路上に高々 1 回出現),その重みは d ( k − 1 ) ( i , k ) + d ( k − 1 ) ( k , j ) である.両者の最小値が d ( k ) ( i , j ) を与える. □
Input:
有向グラフ G = ( V , A ) ,重み w , V = { 1 , … , n } Output:
全頂点対間の最短距離 d [ i ] [ j ] for i = 1 to n
for j = 1 to n
if i = j
d [ i ] [ j ] ← 0
else if ( i , j ) ∈ A
d [ i ] [ j ] ← w ( i , j )
else
d [ i ] [ j ] ← + ∞
end if
end for
end for
for k = 1 to n
for i = 1 to n
for j = 1 to n
d [ i ] [ j ] ← min ( d [ i ] [ j ] , d [ i ] [ k ] + d [ k ] [ j ])
end for
end for
end for
return d
計算量は O ( ∣ V ∣ 3 ) であり,対角成分 d ( n ) ( i , i ) < 0 であれば頂点 i を含む負閉路が存在する.
6 DAG 上の最短路
DAG(有向非巡回グラフ)上の単一始点最短路は,頂点をトポロジカル順序で並べ,その順に各辺を 1 回ずつ緩和するだけで O ( ∣ V ∣ + ∣ E ∣ ) で計算できる.
トポロジカル順序では,辺 ( u , v ) があれば u が v より前に現れる.したがって頂点 v を処理する時点で, v に入る辺 ( u , v ) の始点 u はすべて処理済みであり d [ u ] = δ ( s , u ) が確定している.よって辺 ( u , v ) の緩和により d [ v ] = δ ( s , v ) が正しく得られる. □
関連する「教科書の行間」記事
https://interconnectd.app/articles/LLw6hhxJh2x4jHVESOay