データ構造とアルゴリズム
第十一回
(2012年1月6日)
動的計画法
http://www.sw.it.aoyama.ac.jp/2011/DA/lecture11.html
Martin J. Dürst
© 2009-12 Martin
J. Dürst 青山学院大学
目次
- これからの予定
- 前回の残り・まとめ
- アルゴリズムの設計方針
- 動的計画法の概要
- 応用例: 行列の連鎖乗算の順番
- Ruby による動的計画法
これからの予定
- 1月13日 (金): 12回目の授業
- 1月17日 (火曜日1限、補講): 13回目の授業
- 1月20日 (金): 14回目の授業
- 1月27日 (金曜日1限、9:30-10:55): 期末試験
補講についての注意
期末試験の内容
- 試験範囲:
- 授業・プリント・プログラムの全ての内容
- プログラムそのものは書く必要がないが、理解する必要はある
- 問題の種類:
- 情報数学 I や計算機実習 I と類似
- 過去の問題 (2008年度、2009年度、2010年度):
- 一部のブラウザ (IE7以前) は非推奨
図と解答例の一部は欠落
解答例は「表示」→「スタイル」→「solutions」で表示可能
- 注意点:
- 問題をよく読む (計算、証明、説明などの区別)
- 概念の定義を自分の言葉でおさえる
- 綺麗な字で書く
前回の残り・まとめ
アルゴリズムの設計方針
- 単純なアルゴリズム
- 総当たり方 (腕力方、虱潰し、brute force)
- 貪欲アルゴリズム (greedy algorithm)
部分的な選択で最適な解を得る
- 分割統治法 (divide and conquer)
重複しない部分問題に分割
- 動的計画法 (dynamic programming)
- ネットワークフロー (network flow)
コストをグラフ上に移動しながら最適化
動的計画法の概要
(dynamic programming)
- (最適) 解の構造を調査、明記
- (最適) 解の値を再帰的に定義
- ボトムアップで (最適) 解の値を算出
- 計算した情報から (最適) 解を構築
動的計画法の単純な例
- フィボナッチ関数 f(n) (n は 0
以上の整数):
- n ≦ 1: f(n) = n
- n ≧ 2: f(n) =
f(n-1) + f(n-2)
- 再帰的な定義のため、実装が簡単
- n が大きくなると実行が非常に遅い
- 計算の順番を変えると加速
- 順番を変える代わりに、途中結果の記憶も可能
行列の乗算
- r0 × r1 の行列
0M1 と
- r1 × r2 の行列
1M2 の乗算
(0M1·
1M2 ⇒
0M1M2)
の結果は
- r0 × r2 の行列
0M2
- 乗算の計算量は
r0r1r2
の掛け算と
r0(r1-1)r2
の足し算で
O(r0r1r2)
三行列の連鎖乗算
- 三つ (以上) の行列の乗算:0M1·
1M2 ·
2M3
- 行列の乗算において結合律が成立
- 順番は複数:0M1·
(1M2 ·
2M3) 又は
(0M1·
1M2) ·
2M3
(即ち、0M1M3
又は
0M2M3)
- r0=100, r1=2,
r2=200, r3=3 の場合、
それぞれの順番の場合の掛け算の数:
0M1·
(1M2 ·
2M3): 2×200×3 + 100×2×3
= 1,800
(0M1·
1M2) ·
2M3: 100×2×200 + 100×200×3
= 100,000
乗算の順番の数
乗算の数 |
順番の数 |
0 |
1 |
1 |
1 |
2 |
2 |
3 |
5 |
4 |
14 |
5 |
42 |
6 |
132 |
7 |
429 |
8 |
1430 |
9 |
4862 |
- 最初少なく見えるが、爆発
- パスカルの三角形の真ん中の数 (1, 2, 6, 20, 70,...)
を整数 (1, 2, 3, 4, 5,...) で割ったもの
- カタラン数 (Catalan number)
Cn =
(2n)!/(n!(n+1)!)
= Ω(4n/n3/2)
- 応用が豊富:
- 括弧対の組み合わせの数
- 二分木の数
- (凸) 多角形の三角分割
乗算の最適な順番
- 総当たりで決めるのが無理
- 最低の計算コスト (スケーラ乗算の数、足し算は無視):
- mincost(a, c) は
aMc
の最低の計算コスト
- mincost(a, c) = 0 if a+1 ≧
c,
- mincost(a, c) = minb
(cost(a, b, c))
if a+1 < c
(ただし、a<b<c)
- cost(a, b, c):
aMc の計算を
aMbMc
で行うときのコスト (b は分岐点)
- cost(a, b, c) =
mincost(a, b) + mincost(b,
c) +
rarbrc
最適化の順番と途中結果の記憶
- mincost(0, n) から再帰的に計算が可能
(下向き、トップダウン、top-down)
- 同じ mincost(x, y)
が何回も計算される
- 下から計算 (上向き、ボトムアップ、bottom-up):
- 長さ k (k が順番に 2,...,n)
の連鎖乗算の最低コストを計算
- 計算結果を記憶、再利用
- Ruby による実装: Bmatrix.rb
計算の実例
|
0M1M5:
274
0M2M5: 450
0M3M5: 470
0M4M5: 320 |
|
|
0M1M4:
260
0M2M4: 468
0M3M4: 400 |
1M2M5:
366
1M3M5: 330
1M4M5:
250 |
|
|
0M1M3:
200
0M2M3: 284 |
1M2M4:
360
1M3M4:
220 |
2M3M5:
330
2M4M5: 390 |
|
|
0M1M2:
48 |
1M2M3:
120 |
2M3M4:
300 |
3M4M5:
150 |
|
0M1: 0 |
1M2: 0 |
2M3: 0 |
3M4: 0 |
4M5: 0 |
r0 = 4 |
r1 = 2 |
r2 = 6 |
r3 = 10 |
r4 = 5 |
r5 = 3 |
連鎖乗算の最適化の計算量
- mincost(a, c) の計算量は
O(c-a)
- 全ての mincost(a, a+k)
はO((n-k)·k)
- 合計の計算量は ∑nw=1
O((n-k)·k) =
O(n3)
動的計画法では問題によって
O(n3), O(n2),
O(n),
O(nm) 等さまざまな計算量
動的計画法の概要 (再確認)
- (最適) 解の構造を調査、明記
- (最適) 解の値を再帰的に定義
- ボトムアップで (最適) 解の値を算出
- 計算した情報から (最適) 解を構築
動的計画法の基本要素
- 部分構造の最適性 (optimal substructure)
全体の (最適) 解が部分問題の (最適) 解から構築可能
- 部分問題の重複 (overlapping subproblems)
- 履歴管理 (memoization)
Ruby による履歴管理
- 関数の変更:
- 引数をキーに結果をハッシュ等に記録
- 実際の計算の前に記録を確認、使用
- この技法は memoize と言う
- Ruby ではメタプログラミングによって実装可能
- 簡単な応用例: Bfibonacci.rb
まとめ
- 動的計画法はアルゴリズムの設計方針の一つ
- 全体の解が部分の解から得られるが、部分が重複するのが特徴
- 計算量は問題の構造によって異なる