Transcript Document
コンピュータソフトウェア
9. 最短路(Shortest Path)
田浦
http://www.logos.ic.i.u-tokyo.ac.jp
/~tau/lecture/software/
最短路の問題
2点間を結ぶ最短の道を求める
道の長さとは:
単純な場合(重みなしグラフ): 含む辺の数
複雑な場合(重みつきグラフ): 含む辺についた「重み」
の和
前者ならば幅優先探索が答え.主な興味は後者
1
3
4
3
2
3
1
3 4
7
わかりやすい応用例(1)
渋滞考慮無しのカーナビ
頂点: 交差点
辺 : 2交差点を結ぶ一本道
辺の重み: その一本道を抜けるのにかかる時間(渋滞無し
これが時刻によらず一定)
2点間の最短路 = 2つの交差点間を最も早く移動するドライ
ブルート
クイズ: 一方通行,Uターン禁止,右折禁止などをどうモデル
化する?
わかりやすい応用例(2)
インターネットのルーティング
頂点: ネットワークルータ
辺: ケーブル(インターネットより下のレイヤ(2)で直接通信
できるルータの対)
辺の重み: パケットがそこを通ることに対するコスト
例: バンド幅の関数(バンド幅が大きければ小さい)
2点間の最短路: パケットを配送する適切な道
少し自明でない応用例(1)
時刻表を考慮した路線検索
頂点 (t, A) : 時刻tに駅Aにいるという「状態」
辺:
(t, A) (t + 1, A) : 1単位時間同じ場所にとどまる
(t, A) (u, B) : 時刻tにA駅を発車して時刻uにB駅につ
く列車がある
辺の重み: かかる時間(前者は1, 後者は u – t)
(t, A)から(*, B)への最短路: 時刻tにA駅にいる人が最早
でB駅にたどり着く手段を与える
視覚的に「見るからにグラフ」ではないものが,実はし
ばしばグラフとして表現できる
少し自明でない応用例(2)
(1)と同じ流れで「渋滞考慮ありカーナビ」
いろいろな問題のモデル化が考えられるが最も単純には
「渋滞考慮」=
時刻によって各道を通るのにかかる時間が異なる
各道をある時刻に通る際の通過時間は与えられている
(渋滞の発生は先まで予測できている)
時刻は分刻み,通過時間も分刻みとする
としてモデル化する
(t, A) (u, B) : 交差点AとBが一本道でつながっており,時
刻tにAにいた車は時刻uにBにつける
アルゴリズム
Dijkstra (ダイクストラ)法 (必修)
幅優先探索とほぼ同じ考え方
指定した一頂点から他の全頂点までの最短路(距離)を求
める (一対全)
Floydのアルゴリズム
全ての頂点対間の最短路・距離を求める (全体全)
Dijkstra法: 概要
最前線: 訪問済みから1 hop
優先度つきグラフ探索の一種
頂点uの優先度: これまでに見つ
かっているs * uの最短距離
あとはほぼ「一般的な探索方法」に従う
だけ
入力: 辺重みつき有向グラフG = V, E
とその一頂点s ( V)
辺の重みは非負
アルゴリズムは無向でも同様
出力: D[i] (i V)が,sからiへの最短距
離を与えるような配列D
最短路を与えるように変更するのは
容易
訪問済み
訪問済みから>1 hop
Dijkstra法: 擬似コードdijkstra(s, G) {
4
8
3
1
6
start
4
2
1
5
goal
Wu,v : 辺u vの重み(距離)
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 (意図: 最短距離確定)
緑:暫定最短距離 (startから赤だけを使う道の中での最短距
離)
1
456
4
8
3
1
6
0
start
4
2
1
34
5
goal
9
8
7
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;
頂点i Sに対し,D[i]が「すべて
S = S + { u };
の道の中での」 sからiへの最短
for v adjacents(u) {
距離
d = D[u] + Wu,v ;
if (d < D[v]) D[v] = d;
頂点i Vに対し,D[i]は,「Sの
}
点のみを経由する道の中での」
}
sからiへの最短距離
}
Dijkstra法の正しさ
S
証明
黒板にて
実現の詳細と計算量
基本
whileループは常にn (頂点数)回繰
り返す
ポイント
集合Sの表現とかかわる操作(2行)
単純アプローチ
S : 配列 S[i] = 1 iff i S;
: 線形探索 O(n)
全体の計算量 O(n2)
密なグラフならこれ以上は難しそう
疎なグラフでより高速な方法は?
集合から最小の要素を取り除く!
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法
集合 T = V – S をヒープを用い
た優先度キューで表現
最小値の除去O(log n)
new 優先度の変更 O(log n)
合計計算量
O((n + m) log n)
たとえば m O(n)のグラフ
に限れば O(n log n)
現実の道路・鉄道・ネット
ワークetc.は?
ヒープを用いた優先度キューの簡単な拡張と
して考えてみよ
dijkstra(s, G) {
T = priority_queue(V);
dijkstra(s, G) {
D = new int[n];
S = {};
for (i = 0; i < n; i++) {
D = new int[n];
if (i == s) D[i] = 0;
for (i = 0; i < n; i++) {
else D[i] = ;
if (i == s) D[i] = 0;
}
else D[i] = ;
while (T {}) {
}
delete u T that minimizes D;
while (S V) {
pick u V – S that minimizes D;
for v adjacents(u) {
S = S + { u };
d = D[u] + Wu,v ;
for v adjacents(u) {
if (d < D[v]) {
d = D[u] + Wu,v ;
D[v] = d;
if (d < D[v]) D[v] = d;
change priority of v in T to d;
}
}
}
}
}
}
}
最短路を実際に求
めるには?
配列Dと並行してPを維持
P[i] : D[i]に書かれている(暫
定)最短距離を与える経路上
でのiの先行頂点
s P[i] i
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; P[v] = u; }
}
}
}
全対全最短距離
方法1: Dijkstraを各頂点を開始点として行う
O(n3) または O(n (n + m) log n)
方法2: Floydのアルゴリズム
O(n3)
入力:辺重みつき有向グラフG = V, E
出力: D[i,j] が iからjへの最短距離を与えるような2
次元配列D
Floydのアルゴリズム
仮定:
重みの和が負となる閉路 floyd(G) {
D = new int[n][n]; /* 略記 */
がない
for (i = 0; i < n; i++)
Dijkstraと異なり,負の重
for (j = 0; j < n; j++)
みの辺があってもよい
D[i,j] = Wi,j;
(*)のループの不変条件:
for (k = 0; k < n; k++)
(*)
Sk = { 0, 1, ..., k – 1 }とし
for (i = 0; i < n; i++)
て,D[i,j]はiからjへの道
for (j = 0; j < n; j++)
で,i,jを除いてはSの頂点
D[i,j] = min(D[i,j], D[i,k] + D[k,j]);
であるようなものの中で
}
の最短距離
証明は練習問題
1-1最短距離?
Dijkstra法を使って全頂点までの距離をまず求め,目的地ま
での最短距離を取り出す
1-1だけを(1-全よりも)高速に計算する方法は知られていない