7章 最短路問題(続) 杉原厚吉.(2001).「データ構造とアルゴリズム」. 東京:共立出版. 2011/07/19 情報知能学科「アルゴリズムとデータ構造」 担当:白井英俊 v0からv6への最短路は? v2 2 v1 5 v3 4 v12 8 1 8 v4 2 2 1 1 v0 v11 5 1 v6 1 v13 7 3 6 v5 6 3 1 2 3 v10 2 v9 5 注:青字の数は辺の長さを表す (図6.8から) 1 v8 v7 Shortest-Path アルゴリズム • 入力: グラフG=(V, E), 隣接頂点関数T,長さ関数 l, 始点vs,終点 vt • 出力: vsから vt までの経路の最小値 手続き dは始点からの最短距離を記憶するための配列 1. d(vs) ← 0 V-{ vs } に属すすべての頂点 vに対してd(v) ← ∞ Aは探索すべき頂点を記憶するためのヒープ A ← { vs } Aの中の頂点のうち d が最小の v を取り出す v = vt ならば d(vt) を出力して終了 ヒープの作り直しが必要 T(v) に属す各頂点 w に対して d(w)= ∞ ならAに追加 し、d(w)を計算。 d(w)=d(v)+ l (v,w) それ以外ならd(w)を更新 元のd(w)とd(v)+ l (v,w)の 7. 4へ進む 2. 3. 4. 5. 6. 最小値を新たなd(w)に Shortest-Pathにおけるヒープの役割 • 出発点sから「到達可能な」頂点と、出発点sからの距離 を記憶 • 簡単な動きの解説 1. 登録:始点から到達可能な頂点と、その始点からの距離の見 積もりをすべて登録 2. 取り出し:始点から最短距離にある頂点が順にとりだされる 取り出された頂点は、始点からの最短距離が確定 3. 距離の更新: 「取り出された」頂点を経由する経路による距離 と、見積もりの距離を比較。前者が小さい場合に距離を更新 辺の長さが負でない限り、この方法は、始点からの距離が小さ い頂点を順番に「取り出す」ことを保証する ヒープ(3章から) • ヒープ(heap)とは、特殊な二進木 定義3.2 高さkの二進木Tがヒープであるための 必要十分条件は次の(i), (ii)を満たすこと (i) 深さ0 ~ k-1 の可能な頂点はすべて使われ、 深さkの頂点は左から順に使われている (ii) 頂点uが頂点vの親なら uの値( f(u) ) ≦ ≧ vの値( f(v) ) 最短路探索 親 子 (iii) 「値」だけではなく頂点も記憶 のための修正 ヒープの操作 • 入力データからヒープを作る (1) 新たな要素を値とする頂点をヒープに追加 ⇒ 条件(i)を満たすところに追加 ヒープを配列で実現する場合、「最後の要素のインデック ス+1 」目に要素を追加 (2) 次に、ヒープ条件(ii)を満たすように修正(reform) 付け加えられた要素とその親を比較し交換する、を繰り返す • ヒープから頂点の要素を取り出してから、ヒープをつ くり直す ヒープの最後の要素を『根』に移動し、親と子を比較し、 「小さい」方の子と親を交換する、を繰り返す v0からv12への最短路の長さは?答: V= {vv00, v1, v2, v9, v10, v11, v12} vv22 A d 1 0 2 ∞ 3 1+ ∞3 4 2+ 5 ∞ 5 ∞ 6 1+2 ∞ 4 2 v0 v1 v2 v9 ≦ 2+ v10 v11 2+ 7 ∞ ≦3+ v12 v11 11 11 v0 v12 v11 5 11 5 3 6 7 33 vv10 10 2 v9 1. 4. d(v Aの中の頂点のうち d が最小の v を取り出す s) ← 0 2. に属すすべての頂点 vに対してd(v) ← ∞ 5. V-{ v = vvts }ならば d(vt) を出力して終了 3. A ←に属す各頂点 { vs } 6. T(v) w に対し d(w)= ∞ ならd(w) =d(v)+ l (v,w)を計 算しwをAに追加。それ以外ならd(w)を更新 v0からv6への最短路は? v2 2 v1 5 v3 4 v12 8 1 8 v4 2 2 1 1 v0 v11 5 1 v6 1 v13 7 3 6 v5 6 3 1 2 3 v10 2 v9 5 注:青字の数は辺の長さを表す (図6.8から) 1 v8 v7 課題(教科書 p. 77) 1. 演習問題 7.1 図6.8のグラフで、 vs =v0, vt = v6とおいたときのアル ゴリズムShortest-Pathの振る舞いを示せ。 演習問題 7.1 vs =v0, vt = v6のときのアルゴ リズムShortest-Pathの振る舞い 頂点のリスト(ヒープで表現) 括弧内は始点からの 0 距離(dの値) v 1 2 v1 1 0 (1) v0(0) (2) v1(0+1), v10(0+3) 4 2 1 v11 5 6 3 3 v10 (3) v11(1+1), v2(1+2) , v10(3) (4) v10(3), v2(3), v9(2+3), v12(2+5) (5) v2(3), v12(7), v9(5), (6) v9(5),v12(7), v3(8) (7) v13(5+1), v12(7), v8(5+5) , v3(8) (8) v12(7), v3(6+1<8), v8(6+3<10) (9) v3(7), v8(9), v5(7+2) v2 3 7 5 v3 78 v12 8 1 7 1 2 5 v9 2 6 v13 3 1 3 v4 5 2 9 v5 6 1 9v 2 v7 8 (10) v5(9), v8(9), v4(7+8) (11) v8(9), v4(9+2<15), v6(9+1), (12) v6(10), v4(11), v7(9+1) 答え: v6(10) 10 1 v6 課題(教科書 p. 77) 1. 演習問題 7.1 図6.8のグラフで、 vs =v0, vt = v6とおいたときのアル 済み ゴリズムShortest-Pathの振る舞いを示せ。 2. 演習問題7.2 本日の課題 アルゴリズムShortest-Pathを変更して、頂点vsから 他のすべての頂点までの最短路の長さを求めるア ルゴリズムを作れ。またshortestPath.rbを改変してこ れを実現せよ。 別課題:最短路の経路を返すように改変せよ Shortest-Path プログラム アルゴリズムからプログラムを実現するた めに 1.ヒープの実現 2.グラフの表現 を考える必要がある ヒープの実現 heap4Graph.rbファイル参照 • ヒープを作る: 例 h = Heap.new • ヒープhに要素sを追加: 例 h.insert(s) • ヒープhの根を削除し、ヒープの修正を行う。削除さ れたヒープの根の要素を返す 例 s = h.delete_min • ヒープhから要素xを見つけ、インデックスを返す 例 y=h.find(x) • ヒープhのインデックスy(その要素の値の変更)に注 目してヒープを作り直す 例 h.up_heap(y) ヒープの実現 heap4Graph.rbファイルから class Heap def initialize # ヒープを配列で実現 @size = 0 # ヒープが空かどうかの判定 @data = [nil] def empty ... end # 最小値を返す def delete_min ... end # fromからtoまでの番号でヒープをつくり直す def down_heap(from,to) ... end # ヒープに値xを付け加える def insert(x) ... end # ヒープから値xをもつ要素を探しその番号を返す def find(x) ... end グラフの表現 • グラフ探索の場合とほぼ同じ考え方 • ただし、辺の長さを記録する必要がある 隣接頂点と辺の長さの対 class Arc def initialize(x,y) @node = x @distance = y end # def def value return @distance end end # class グラフの頂点の表現 グラフ探索とほぼ同じだが、インスタ ンス変数edgeの値に変更あり class GraphNode def initialize(x="") @label=x @edges=Hash.new(false) end # def attr_accessor :label, :edges グラフの頂点:辺の長さの記録 参考 class Arc def initialize(x,y) @node = x @distance = y end # def class GraphNode def initialize(x="") @label=x @edges=Hash.new(false) end # def def addEdge(arc) if (arc.class == Arc) && (@edges[arc.node] == false) @edges[arc.node] = arc.distance end # if end # def これにより、v1からv2への辺の長さが v1.edges[v2] で得られる(辺がなければ falseを返す) グラフの表現 v = Array.new vは頂点の配列 for i in 0..13 v[1], v[2], …などによって v[i]=GraphNode.new("v#{i}") 頂点v1, v2,…を取り出せる ようにする end Edges = [ Edgesの要素一つ一つを取り出し、 [v[0], [Arc.new(v[1],1), 頂点それぞれに辺の情報を記録 Arc.new(v[10],3)]], Edges.each do |x| [v[1], [Arc.new(v[0],1), x[1].each do |z| Arc.new(v[11],1), Arc.new(v[2],2)]], x[0].addEdge(z) 中途略 end end ] Edgesは [ 頂点、 辺のリスト] を要素とする配列 Shortest-Path アルゴリズム • 入力: グラフG=(V, E), 隣接頂点関数T,長さ関数 l, 始点vs,終点 vt • 出力: vsから vt までの経路の最小値 手続き dは始点からの最短距離を記憶するための配列 1. d(vs) ← 0 V-{ vs } に属すすべての頂点 vに対してd(v) ← ∞ Aは探索すべき頂点を記憶するためのヒープ A ← { vs } Aの中の頂点のうち d が最小の v を取り出す v = vt ならば d(vt) を出力して終了 ヒープの作り直しが必要 T(v) に属す各頂点 w に対して d(w)= ∞ ならAに追加 し、d(w)を計算。 d(w)=d(v)+ l (v,w) それ以外ならd(w)を更新 元のd(w)とd(v)+ l (v,w)の 7. 4へ進む 2. 3. 4. 5. 6. 最小値を新たなd(w)に Shortest-Pathプログラム def shortestPath(s,t) # sは始点、tは終点 1. d(vs) ← 0 $dist[s]=0 # $dist はすべての頂点に対してsからの距離を記録 2. V-{ vs } に属すすべての頂点 v h = Heap.new # h はヒープ に対してd(v) ← ∞ h.insert(s) # まずhに始点を登録 3. A ← { v } s loop { # 繰り返し 4. Aの中の頂点のうち d が最小の v を取り出す s = h.delete_min # ヒープの根(最小距離の頂点)を取り出す 5. v = vt ならば d(vt) を出力して break if (t == s) # それが終点なら終了 終了 s.adjacentNodes.each do |x| # sの隣接頂点それぞれ(x)に対し 6. T(v) に属す各頂点 w に対して updateDist(s,x,h) d(w)= ∞ ならAに追加し、d(w)を end # each 計算。 それ以外ならd(w)を更新 } 4 へ進む return $dist[t] # 始点から終点までの距離を返す end # def def updateDist(s,x,h) # 距離の更新 if ($dist[x] == Max) # 始点からxまでの距離がMaxなら # 「(s,x)の長さ+始点からsまでの距離」をxの距離として登録 $dist[x] = arclength(s,x)+$dist[s] h.insert(x) # xをヒープに登録 else # 上記以外というのは、xが登録済の場合 # 「(s,x)の長さ+始点からsまでの距離」をzとする z = arclength(s,x)+$dist[s] if (z < $dist[x]) # zと登録されたxの距離を比較 $dist[x] = z #zの方が小さければzの値を登録 h.up_heap(h.find(x)) # ヒープの作りなおし end # if end # if end # def 演習問題7.2 • アルゴリズムShortest-Pathを変更して、頂点vsから他のすべて プログラム の頂点までの最短路の長さを求めるアルゴリズムを作れ。 ここが終了条件。 手続き 1. d(vs) ← 0 vtで止めなければすべての頂点を調べる? 2. V-{ vs } に属すすべての頂点 vに対してd(v) ← ∞ 3. A ← { vs } 4. Aの中の頂点のうち d が最小の v を取り出す 5. (5の項目を削除) v = vt ならば d(vt) を出力して終了 6. T(v) に属す各頂点 w に対して d(w)= ∞ ならAに追 加し、d(w)を計算。 それ以外ならd(w)を更新 7. 4へ進む Aが空ならdを返して終了。さもなくば4へ進む ただし、これでは終了条件がなくなるので… 演習問題 • アルゴリズムShortest-Pathを変更して、頂点sから頂点tまでの 最短路の長さと、経路(sからtまでのパスの上の頂点の列)を 求めるアルゴリズムとプログラムを作れ。 手続き r をハッシュ表とする r(vs ) ← [vs ] # 値はリスト/配列とする 1. d(vs) ← 0 2. V-{ vs } に属すすべての頂点 vに対して r(v ) ← [ ] d(v) ← ∞ 3. A ← { vs } 4. Aの中の頂点のうち d が最小の v を取り出す 5. v = vt ならば d(vt) と r(vt ) を出力して終了 6. T(v) に属す各頂点 w に対して d(w)= ∞ ならAに追 加し、d(w)を計算。 r(w) ← r(v)+[w] # リスト/配列の接合 それ以外ならd(w)を更新 値を更新するなら 7. 4へ進む r(w) ← r(v)+[w] 質問がなければ • これらのプログラムの完成を出欠レポートの 課題とします • できない場合は宿題(締切りは7月18日)
© Copyright 2024 ExpyDoc