1 / 45

09. 最短路

09. 最短路. 五島. 深さ優先以外の探索. 当然こちらを先に選ぶことも可能. 深さ優先以外の探索. 深さ優先探索: 「 visit した先にある」頂点を次に visit 一般 に は, 訪問済み 頂点に隣接したどの頂点も次に 訪問可能. 深さ優先探索が選ぶ頂点 :. 様々な探索戦略. 一般の優先度探索: 目的に応じた判断基準で優先度を決める 深さ優先探索 (depth first search) 開始点から遠い頂点を先に 幅優先探索 (breadth first search) 開始点に近い頂点を先に. 0. 1. 2. 3.

sunila
Download Presentation

09. 最短路

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 09. 最短路 五島

  2. 深さ優先以外の探索

  3. 当然こちらを先に選ぶことも可能 深さ優先以外の探索 • 深さ優先探索: • 「visit した先にある」頂点を次に visit • 一般には, • 訪問済み頂点に隣接したどの頂点も次に訪問可能 深さ優先探索が選ぶ頂点:

  4. 様々な探索戦略 • 一般の優先度探索: • 目的に応じた判断基準で優先度を決める • 深さ優先探索 (depth first search) • 開始点から遠い頂点を先に • 幅優先探索 (breadth first search) • 開始点に近い頂点を先に 0 1 2 3 深さ優先 4 0 1-1 1-2 5 2-1 2-2 2-3 2-4 幅優先

  5. visited[v] = 1  or 探索の一般形 最前線: 訪問済みから1 hop visit(s, G, visited) {F = { s }; /* Frontier */visited[s] = 1; while (F {}) {u = F.delete_one(); for v adjacents(u) { if (visited[v] == 0) {visited[v] = 1;F.add(v); } } }} 訪問済み ここでどのノードを選ぶか(だけ)で探索順序が決まる 訪問済みから>1 hop

  6. 様々な探索戦略の実現 • 深さ優先探索 • Fの中で最後に Fに入ったものを選ぶ • Fをスタック (Last-In-First-Out; LIFO) にする • コードでは,再帰呼び出しのコール・スタックで実現 • 幅優先探索 • Fの中で,開始点からの深さが最小のものを選ぶ • Fをキュー (First-In-First-Out: FIFO) にする • 一般の優先度探索 • 目的に応じた判断基準で優先度を決定 • Fを優先度付きキュー (priority queue) とする

  7. 反復深化探索 • 深さ制限つき深さ優先探索 • 深さ優先探索を,開始点からの距離(再帰呼び出しを使うならその呼び出しの深さ)に制限をつけて行う • 反復深化 • その深さ制限を徐々に増やしながら深さ優先探索を繰り返す • 利益: • 深さ優先と同じメモリ量 • visited配列を記憶しなくても,無限ループはしない • 幅優先に似た広く浅い探索 • 浅い探索の結果を,「解の有望度」として,深い探索の順序制御に用いることができる

  8. 幅優先探索の性質 • 幅優先探索によってたどられた辺(visited[v] = 1の実行を引きおこしたu  v)の集合は,sから各頂点への最短路(最小の辺数で到達する道)を与える「重みなしグラフ(重み一律)の最短路の問題」 bfs_visit(s, G, visited) {F = queue(s); /* C++ deque/list, Java : LinkedList */visited[s] = 1; while (not F.is_empty()) {u = F.deq(); /* 前から出す */ for v adjacents(u) { if (visited[v] == 0) {visited[v] = 1;F.enq(v); /* 後ろに入れる */ }}}} 1 4 7 9 3 8 6 0 5 2

  9. 最短路

  10. 最短路の問題 • 2点間を結ぶ最短の道を求める • 道の長さ: • 重みなしグラフ: 含まれる辺の数,ホップ数 • 重みつきグラフ: 含まれる辺についた重みの和 1 4 3 2 3 4 3 7 1 3

  11. わかりやすい応用例 (1/2) • 渋滞考慮無しのカーナビ • 頂点:交差点 • 辺: 2交差点を結ぶ一本道 • 辺の重み:その一本道を抜けるのにかかる時間 • 渋滞無し  重みが時刻によらず一定 • 2頂点間の最短路: 2つの交差点間を最も早く移動するドライブ・ルート • クイズ: • 一方通行,Uターン禁止,右折禁止などをどうモデル化する?

  12. わかりやすい応用例 (2/2) • インターネットのルーティング • 頂点:ネットワーク・ルータ • 辺:ケーブル • インターネットより下のレイヤ(2)で直接通信できるルータの対 • 辺の重み:パケットがそこを通ることに対するコスト • ex) バンド幅の関数(バンド幅が大きければ小さい) • 2頂点間の最短路: パケットを配送する適切な道

  13. 少し自明でない応用例 (1/2) • 時刻表を考慮した路線検索 • 頂点 (t, A) : 時刻 t に駅 A にいるという「状態」 • 辺: • (t, A)  (u, B):時刻 tに A駅を発車して時刻 uに B駅につく列車がある • (t, A)  (u, A):時刻 t から u まで A駅にとどまる • 辺の重み: かかる時間(上の例では u – t) • (t, A) から (*, B)への最短路:時刻 tに A駅にいる人が最早で B駅にたどり着く経路 • 一見グラフではないものが,しばしばグラフとして表現できる

  14. 少し自明でない応用例 (2/2) • 編集距離 • 例 • 数字間の類似度は,その絶対差 • 3 と 4の類似度は,|3−4|=1 • ギャップ-と数字の類似度は3 • 数字列の類似度は,対応する数字,ギャップ間の類似度の総和 • 1234と124-の類似度は,0+0+1+3=4. • 右の例の答え: • 01-49 と • 0263-

  15. アルゴリズム • 幅優先探索 • 重みなしグラフのみ • Dijkstra (ダイクストラ)法 (必修) • 幅優先探索とほぼ同じ考え方 • 指定した一頂点から他の全頂点までの最短路を求める (一対全) • Floyd のアルゴリズム • 全ての頂点対間の最短路を求める (全体全)

  16. 幅優先探索と最短路 • 幅優先探索によって visit された頂点は,開始点からの最短路「重みなしグラフ(重み一律)の最短路の問題」 bfs_visit(s, G, visited) {F = queue(s); /* C++ deque/list, Java : LinkedList */visited[s] = 1; while (not F.is_empty()) {u = F.deq(); /* 前から出す */ for v adjacents(u) { if (visited[v] == 0) {visited[v] = 1;F.enq(v); /* 後ろに入れる */ }}}} 1 4 7 9 3 8 6 0 5 2

  17. Dijkstra 法

  18. Dijkstra 法 の 概要 • 優先度つきグラフ探索の一種: • これまでに見つかっている s* u の距離が最短の u を優先して visit • あとはほぼ「一般的な探索方法」に従うだけ • 入力: 重みつきグラフ G = A, Eとその一頂点 s (A) • 辺の重みは非負 • アルゴリズムは無向でも同様 • 出力: D[i] (iA) が,sから iへの最短距離を与えるような配列 • 最短路を与えるように変更するのは容易

  19. Dijkstra 法の概要 F ∞ 2 12 10 ∞ 1 0 9 10 V U 1 ∞ p 10 11 1 V : visited q ∞ U : unvisited F : frontier

  20. 4 8 3 1 6 2 1 start goal 4 5 dijkstra(s, G) {V= {};D = new int[n]; for (i = 0; i < n; i++) { if (i == s) D[i] = 0; else D[i] = ; } while (V  A) { pick uVthat minimizes D;V= V+ { u }; for v adjacents(u) {d = D[u] + Wu,v ; if (d < D[v]) D[v] = d; } }} Dijkstra 法:擬似コード Wu,v:辺u vの重み(距離)

  21. 1 1 1 1 4 4 5 4 1 6 0 0 0 0 3 3 3 3 7 8 9 7 0 4 Dijkstra法の動き • 赤:S (意図:最短距離確定) • 緑:暫定最短距離(startから赤だけを使う道の中での最短距離) 4 8 3 1 6 2 1 start goal 4 5

  22. 証明 F ∞ 2 12 10 ∞ 1 0 9 10 V U 1 ∞ p 10 11 1 V : visited q ∞ U : unvisited F : frontier

  23. 証明 • 前半 • V 内の最短路は確定していると仮定 • U 内の仮距離は,V 内の頂点のみを経由して到達できる最短の長さ • 仮距離が最小の頂点 p(F) を選んだとき,p までの最短路が V 内の頂点のみからなることを言えば,p までの最短路を確定できる. • pまでの最短路が V 内の頂点のみからなる: • U 内の頂点を経由して p に至る最短路があると仮定, • その経路上,F 内の頂点を q とする. • distance(s, p)> distance(s, q) + distance(p, q), distance(p, q) ≥ 0 • distance(s, p)>distance(s, q) となり,矛盾.

  24. dijkstra(s, G) {V= {}; D = new int[n]; for (i = 0; i < n; i++) { if (i == s) D[i] = 0; else D[i] = ; } while (V A) { pick uVthat minimizes D; V= V+ { u }; for v adjacents(u) {d = D[u] + Wu,v ; if (d < D[v]) D[v] = d; } }} 計算量 • 基本 • while ループは常に n(頂点数)回繰り返す • ポイント • 集合 D の表現と操作(2行) • 単純アプローチ • S:配列 V[i] = 1 iffi V; • :線形探索 O(n) • 全体の計算量 O(n2) • 密なグラフならこれ以上は難しそう

  25. dijkstra(s, G) {S = {};D = new int[n]; for (i = 0; i < n; i++) { if (i == s) D[i] = 0; else D[i] = ; } while (S V) { pick uV – S that minimizes D; S = S + { u }; for v adjacents(u) {d = D[u] + Wu,v ; if (d < D[v]) D[v] = d; } }} dijkstra(s, G) {T = priority_queue(V);D = new int[n]; for (i = 0; i < n; i++) { if (i == s) D[i] = 0; else D[i] = ; } while (F {}) { delete uF that minimizes D; for v adjacents(u) {d = D[u] + Wu,v ; if (d < D[v]) {D[v] = d; change priority of v in Fto d; } } }} 疎なグラフ用の Dijkstra 法 • 集合 Fをヒープで表現 • 最小値の除去: O(log n) • 優先度の変更: O(log n) • 合計計算量 • O((n + m) log n) • m O(n) ならば O(n log n) • 現実の道路・鉄道・ネットワークetc.は?

  26. ヒープ • 二進木 • 親 < 子(または,親 > 子) • 挿入,削除: O(log n) 1 0 1 2 3 2 0 0 1 1 1 1 2 3 2 2 3 2

  27. 全対全 最短距離 • 方法 1: Dijkstra 法を各頂点を開始点として行う • O(n3) または O(n (n + m) log n) • 方法 2: Floydのアルゴリズム • O(n3)

  28. Floyd のアルゴリズム

  29. Floyd のアルゴリズム • 概要: • 全対全 最短距離 • O(n3) • 入出力: • 入力: 辺重みつき有向グラフ G = V, E • 出力:D[i][j] が iから jへの最短距離を与えるような 2次元配列 D • 仮定: • Dijkstra 法と異なり,負の重みがあってもよい • 重みの和が負となる閉路がない

  30. Floyd のアルゴリズム • (*) のループの不変条件: • D[k][i][j] は, • iから jへの道で, • 0, 1, …, kのみを経由する • 最短路の長さ int D[−1:n−1][0:n−1][0:n−1]; floyd(graph G) { for (i = 0; i < n; i++) for (j = 0; j < n; j++) D[−1][i][j] = G.weight(i,j); for (k = 1; k < n+ 1; k++) // (*) for (i = 0; i < n; i++) for (j = 0; j < n; j++) D[k][i][j] = min(D[k − 1][i][j] , D[k − 1][i][k] + D[k − 1][k][j]; }

  31. 考え方 • 考え方: • D[k − 1][i][j]:0, 1, …, k − 1 のみを経由する i, j間の最短距離 から • D[k][i][j]: 0, 1, …, k − 1, k のみを経由する i, j間の最短距離 を求める • 言い替え: • D[k − 1][i][j]: 0, 1, …, k − 1 のみを経由する i, j間の最短距離 が正しく分かっているとして,さらに k も経由していいとしたら,どうすればいいか?

  32. k回目のイタレーション 0, 1, …, k − 1 のみを経由する i, j間の最短距離 D[k − 1][i][j] i j D[k − 1][i][k] D[k − 1][k][j] 0, 1, …, k − 1 のみを経由する i, k間の最短距離 0, 1, …, k − 1 のみを経由する k, j間の最短距離 k D[k][i][j] = min(D[k − 1][i][j], D[k − 1][i][k]+ D[k − 1][k][j]) 0, 1, …, kのみを経由する i, j間の最短距離

  33. k = 0回目のイタレーション どこも経由しない i, j間の最短距離 D[−1][i][j] i j D[−1][i][0] D[−1][0][j] どこも経由しない i, 0 間の最短距離 どこも経由しない 0, j間の最短距離 0 D[0][i][j] = min(D[−1][i][j], D[−1][i][0]+ D[−1][0][j]) 0 のみを経由する i, j間の最短距離

  34. k = 1 回目のイタレーション 0 のみを経由する i, j間の最短距離 D[0][i][j] i j D[0][i][1] D[0][1][j] 0 のみを経由する i, 1 間の最短距離 0 のみを経由する 1, j間の最短距離 1 D[1][i][j] = min(D[0][i][j], D[0][i][1]+ D[0][1][j]) 0, 1 のみを経由する i, j間の最短距離

  35. 動作例 0 3 1 1 1 3 1 2 1 D[k = 0]:0 を経由 D[k = 2]:0, 1, 2 を経由 D[k = −1]:初期化後 D[k = 1]:0, 1 を経由 D[k = 3]:0, 1, 2, 3 を経由

  36. Floyd のアルゴリズム • D は2次元でよい • 単に3次元目を省略 → • 記憶量は O(n2) でよい int D[n][n]; floyd(graph G) { for (i = 0; i < n; i++) for (j = 0; j < n; j++) D[i][j] = G.weight(i,j); for (k = 0; k < n; k++) // (*) for (i = 0; i < n; i++) for (j = 0; j < n; j++) D[i][j] = min(D[i][j] , D[i][k] + D[k][j]; }

  37. 一対一 最短距離

  38. 一対一 最短距離? • 一対一 最短距離: 与えられた2点間の最短距離を求める • Dijkstra 法(一対全)を使って全頂点までの距離をまず求め,目的地までの最短距離を取り出す • 一対一だけを(一対全よりも)高速に計算する方法は知られていない

  39. 探索問題

  40. 抽象的(暗黙的)なグラフ • データ構造として表せないようなグラフ • ex) 巨大 • 抽象的(暗黙的)なグラフ: • 隣接点の集合 adjacents(u) が計算できれば,「グラフ」と見ることが可能 • ex) ゲームのグラフ • 頂点:ゲームの状態(盤面) • u v:状態 uから状態 vへ「一手で」移ることが可能

  41. 探索問題 • これまで述べた探索アルゴリズムは,抽象的なグラフに対しても適用可能 • 巨大な状態空間の中からある性質を持った「ゴール・解」の「探索」 •  このような問題をしばしば「探索問題」と呼ぶ

  42. 練習問題 • グラフ探索の考え方を使って,「8パズル」を解くプログラムを書いてみよ グラフのノード数(の上界)は? 連結(どこからでもゴールできる)か? 最短(最小手数)でゴールするには? 2 3 4 7 1 5 8 6 2 3 4 7 1 5 8 6 1 2 3 4 5 6 7 8 ゴール

  43. 探索問題の困難と戦略 • 困難:探索空間が巨大(頂点数 nが大きい) • すべてを探索するには時間がかかりすぎる • メモリに収まりきらない (visited配列すべてを記憶できない) • 目的: • 特定の頂点(ゴール,解)を見つけることで, • 全頂点を見る必要はない • ゴールに早くたどり着く戦略(経験則,heuristics)が必要

  44. いくつかの経験則・戦略 • 隣接頂点 adjacents(u) の順序付け • 答えに到達する可能性が高い頂点を先に探索 • 頂点の「有望度」(例:解への近さ)を測る経験則が必要 • メモリの節約 • 深さ優先探索で訪問済み頂点 (visited) を記憶しない • 同じ頂点を 2度訪問してしまう危険性? • グラフが木で,あり得ない場合 • 許容される場合 • 浅く広いグラフの場合になお有用(必要メモリ量 O(深さ))

  45. 挑戦しがいのある課題 • 15パズル,ルービックキューブなど,状態空間が大きいパズルの解法 • ルービックキューブくらいなら課題2として良いかも

More Related