回 2-9 道 2 データ構造とアルゴリズム
動的計画法は、
読み終えたら素直な
この頁の流れ
同じ
同じ 計算を、 何万回も していないか
動的計画法 (どうてきけいかく
前の
これを
動的計画法は どう 速くするのか
動的計画法は、
素直な 再帰は、 同じ 問いを 何度も解き直す
素直な
fib(5) は
下の
メモ化は、 上から 解きながら 答えを覚える
メモ化 (memoization) は、
Python では標準の functools.cache をlru_cache(maxsize=None) と
cache をcache_info() が
下から 埋める やり方は、 小さい 方から表を作る
下から
フィボナッチ数なら、
下の
2 つの
| メモ化 (上から) | 表 (下から) | |
|---|---|---|
| 書き方 | 再帰に | ループで |
| 解く部分問題 | 呼ばれた物だけ | 表の |
| 呼び出しの深さ | n に | 深くならない |
| 覚える量の節約 | しにくい | 直前の |
部分問題と 漸化式を立てる
動的計画法が
部分問題 (ぶぶんもんだい
階段の
階段の上り方の漸化式
ways(n) = ways(n - 1)
+ ways(n - 2)
ways(0) = 1, ways(1) = 1この
動かして確かめる
1 本目は、
動かす 素直な再帰の呼ばれた回数
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
fib(6) は 25 回
5 5 15 -
10 55 177 11.8
15 610 1973 11.1
20 6765 21891 11.1
25 75025 242785 11.1
fib(20) の中で
fib 19 1
fib 10 89
fib 2 4181
fib 1 6765n が
2 本目は、
動かす メモ化と表で回数を数える
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
上から 75025 26
表から読んだ 23
本体を動かした 26
呼ばれた 49
下から 75025 24
0 1 1 2 3 5 8 13 21 34 55メモ化では、
3 本目は、
動かす 階段の上り方を表で求める
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
1 1 通り
2 2 通り
3 3 通り
4 5 通り
5 8 通り
6 13 通り
7 21 通り
8 34 通り
9 55 通り
10 89 通り
45 段 18363119031 段から
動的計画法は どこで 崩れるのか
動的計画法は、
大きい 硬貨から 取ると、 枚数が 最小にならない
硬貨の
動的計画法では、
動かす 貪欲法と表で枚数を比べる
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
6 円 貪欲 3
6 円 表 2
外れる金額 [6, 10, 14, 18]
日本の硬貨で外れる 06 円を
貪欲法は、
上からの 書き方は 呼び出しの 深さで 止まり、 表は 大きさで止まる
メモ化はRecursionError で
動かす 深さと表の大きさ
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
上限 1000
3000 は止まった
下から 3000 の桁数 627
3500 行どうし 12257001 マス
品物 20 個の選び方 1048576 通り
上限 10 億の表 21000000021 マス手元の
表は
動的計画法は 仕事で どう 確かめるのか
仕事では、
- 部分問題を
1 文で 決める。 「dp[a] は a 円を 作る 最小の 枚数」のように、 表の 1 マスが 何の 答えかを書く - 部分問題に
持たせる 値は、 その先の 計算に 効く 物だけに する。 引数が 増える ほど 表の マスが増える - 漸化式と、
いちばん小さな 答え (dp[0] など ) を書く - 埋める
順を 決める。 dp[k] を 埋める とき、 使う マスが もう 埋まっている順にする - 小さな
入力で 全探索と 答えが 一致するかを 試験で 確かめる。 上の 硬貨のように 全部比べると 外れる 入力が見つかる - Python なら
cache_info()で、表から 読んだ 回数が 0 でないかを 見る。 0 なら 同じ 部分問題が 出ておらず、 表に 残しても 速くならない
関わる実例
差分を 出す道具 diff は 最長共通部 分列を 解いている (1976年7月)
2 つの
報告は、
崩れた
今の
動かす 最長共通部分列で残る行を出す
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
残る行 ['a', 'b', 'e']
マスの数 64
0 0 0 0 0 0 0 0
0 0 1 1 1 1 1 1
0 0 1 2 2 2 2 2
0 0 1 2 2 2 2 2
0 0 1 2 2 2 2 2
0 0 1 2 2 2 2 3
0 0 1 2 2 2 2 3
0 0 1 2 2 2 2 3a、
出典は An Algorithm for Differential File Comparison (Hunt と
よくある問い
メモ化と 表を 下から 埋める やり方は、 どちらを 使えば よいですか
まずメモ化で
ナップサック問題とは何ですか
重さと
動的計画法は 誰が 考えたのですか
Richard Bellman の
確認クイズ
答えだと
1 問目
素直な
2 問目
この
本体が動いた回数
from functools import cache
body = 0
@cache
def f(n):
global body
body += 1
if n < 2:
return n
return f(n - 1) + f(n - 2)
f(10)
print(body)3 問目
硬貨が
説明課題
フィボナッチ数を
自分の
この回の 先の一歩
同じ
もっと深く
この
一次資料
どれも
- functools (Python 公式文書、英語)。
cacheがlru_cache(maxsize=None)と同じである こと、 引数が ハッシュできる 値に 限られること、 cache_info()がhits と misses を返すこと - sys (Python 公式文書、英語)。
getrecursionlimit()が呼び出しの 深さの 上限を返すこと - An Algorithm for Differential File Comparison (Bell 研究所の
報告 41、 1976年7月、英語)。diff が 最長共通部 分列を 解く こと、 P[i][j] の 漸化式、 時間も 場所も 行数の 積に 比例する こと、 3500 行での 時間、最初の例 - Overview (GNU diffutils 公式文書、英語)。基本の
手順が Myers の 1986 年の 論文 An O(ND) Difference Algorithm and its Variations にあること - The Theory of Dynamic Programming (RAND 研究所 P-550、英語)。Bellman が
1954年9月2日に アメリカ数学会の 夏の 会合で 行った 講演の 原稿であること
次へ
道 2 データ構造とアルゴリズムの回
- 2-0アルゴリズムとは順次、
分岐、 反復の 3 つで書く手順頁で読む - 2-1線形探索と二分探索100 万件でも
20 回で見つかる頁で読む - 2-2バブルソートと
挿入・選択ソート遅い ソート 3 つ、 2 倍で 約 4 倍頁で読む - 2-3クイックソートと
マージソート速い ソート 2 つ、 平均と最悪頁で読む - 2-4スタックとキュー積む順と並ぶ順頁で読む
- 2-5再帰自分を
呼んで 小さくする頁で読む - 2-6木と
二分探索木たどる 順、片寄り頁で読む - 2-7ハッシュテーブル鍵から
一気に 引く、衝突頁で読む - 2-8ダイクストラ法と最短経路点と
線、 幅優先、 重みのある道頁で読む - 2-9動的計画法同じ
計算を 2 度しないこの回 - 2-10試験と
面接で確かめる基本情報 科目B、 道場 10 問、 面接 20 問頁で読む
