動的計画法とは、アルゴリズムの形の一つである。
具体的な例で考えてみよう。東京から大阪まで陸路で移動する最短ルートを検索せよ、といった問題があるとする。
最も単純な回答は、考えられるルートの組み合わせを全部並べて、その中で一番短いものを探す方法だが、これはどう考えても効率が悪い。
例えば、名古屋を経由するルートに注目すると、「東京→名古屋の全パターン」×「名古屋 → 大阪の全パターン」の組み合わせを考える必要があるわけだが、その大部分は99%同じルートでどこか100メートルだけ違う道みたいなものが延々並ぶので、一々すべて計算するのは時間の無駄なわけである。
ところで、東京→名古屋の最短経路、名古屋→大阪の最短経路がそれぞれ分かっていると仮定すると、当たり前だが
東京→名古屋→大阪の最短経路 = 東京→名古屋の最短経路 + 名古屋→大阪の最短経路
になる。東京→名古屋間でどのようなルートを通ろうと、名古屋→大阪間の選択には影響しないので、この分割ができれば無駄な組み合わせを大幅にカットすることができる。
この考え方は当然ながらもっと細かく適用できる。東京→名古屋の最短経路は長野経由か静岡経由のどちらかの最短経路を考えればいいだろうということになるし、どちらのルートも手近な首都高インターまでは共通というような感じになる。あるいは名古屋を経由しないで中央道から北陸に抜けたらどうなるかという可能性について考慮するなら、長野のジャンクションまでは使いまわせるだろう。
これをパターンとして抽出すると、次のように説明できる。
このようなパターンで問題を分割し、必要な計算量を最適化する方法を動的計画法という。
高校数学に出てくるnCr。これはn個の中からr個取り出す組み合わせが何通りあるかを表している。例えば、{A,B,C,D,E}の中から3つを選ぶ組み合わせは、{A,B,C}, {A,B,D}, {A,B,E}, {A,C,D}, ..., {C,D,E}の10通りである。単純にnCrを求めるには教科書に載っていれば公式を使えばよい。しかし、予め必要な範囲を事前に計算して配列に入れておくことでプログラムを高速化することができる場合がある。このようなときに使われるのがパスカルの三角形である。
nCr=n-1Cr-1+n-1Cr
なんとなく漸化式っぽく見えると思う。これを使って動的計画法を説明していく。動的計画法では表に数値を書き込んでいくように計算を行う。まずは表を用意する。続いて一番最初の答えを書き込む。ここでは0C0=1を書き込む。(0個の中から0個取り出す組み合わせは1通りである。)
n↓ r→ | 0 | 1 | 2 | 3 | 4 |
0 | 1 | ||||
1 | |||||
2 | |||||
3 | |||||
4 |
続いて公式を使って、一つ前の計算結果から次の計算結果を計算できるところを順に埋めていく。ここでは2行目のn=1の部分を埋めていく。公式はnCr=n-1Cr-1+n-1Crとなっているので、nCrを計算するにはn-1Cr-1とn-1Crを足せば良い。これは、計算しようとしているマス目の左上と上のマス目の値を足せばそのマス目の値が計算できるということである。
n↓ r→ | 0 | 1 | 2 | 3 | 4 |
0 | 1 | ||||
1 | 1 | 1 | |||
2 | |||||
3 | |||||
4 |
ここで、空欄となっているところや、表の外側に出た部分は0として扱っている。同様に次の行も埋めていく。
n↓ r→ | 0 | 1 | 2 | 3 | 4 |
0 | 1 | ||||
1 | 1 | 1 | |||
2 | 1 | 2 | 1 | ||
3 | |||||
4 |
n↓ r→ | 0 | 1 | 2 | 3 | 4 |
0 | 1 | ||||
1 | 1 | 1 | |||
2 | 1 | 2 | 1 | ||
3 | 1 | 3 | 3 | 1 | |
4 | 1 | 4 | 6 | 4 | 1 |
int main() { static const int N = 30; int C[N][N]; memset(C, 0, sizeof(C)); C[0][0] = 1; for (int n = 1; n < N; ++n) { C[n][0] = C[n - 1][0]; for (int r = 1; r < N; ++r) { C[n][r] = C[n - 1][r - 1] + C[n - 1][r]; } } }
以下、執筆求む
以下、執筆求む
掲示板
6 ななしのよっしん
2016/12/18(日) 23:35:04 ID: VHW4OHtJrF
ここの定義だと単に漸化式とか再帰的アルゴリズムのことを言ってるだけだよな。
必須定義:
* 問題全体は部分部分の結果を足せば出る
* 一度解いた問題は二度解かない <- これ重要
** 単に割ってくだけの作りだと同じサブ問題があちこちに出てダブることがあるので、その時は前の結果を使いまわす
必須ではないけどデフォ:
* そうやってベストケースな組み合わせを効率良く探す
7 ななしのよっしん
2016/12/19(月) 00:26:48 ID: VHW4OHtJrF
そもそも動的「計画法」という名前は、最終結果はとりあえず置いといて、先にどんな材料があれば答えが出るか決めちゃおうというところから来てる。
一般的にでかい問題は分割統治して、それぞれ別に作った結果を最後にがっちゃんこするってのがよくあるセオリーなわけだが、それぞれが完全に独立でやっちゃうと部品の共通化ができなくてすげー効率が悪いわけよ。だから元締め側でそこは管理して「これは余所で用意したのと一緒だからそれを使いまわす」という風に車輪の再発明をしないというのがミソなわけだ。
ただ普通の計画と違って部品を作りながら足りないところを増やしていくから動的だという言い方をする。
8 ななしのよっしん
2019/05/29(水) 17:23:23 ID: f880YqjIl6
提供: おしる子
提供: Qさん
提供: しつね
提供: kurosu
提供: undop-S
急上昇ワード改
最終更新:2025/04/03(木) 07:00
最終更新:2025/04/03(木) 07:00
ウォッチリストに追加しました!
すでにウォッチリストに
入っています。
追加に失敗しました。
ほめた!
ほめるを取消しました。
ほめるに失敗しました。
ほめるの取消しに失敗しました。