SlideShare a Scribd company logo
1 of 59
Download to read offline
2010/03/19 代々木オリンピックセンター (情報オリンピック春合宿)




  プログラミングコンテストでの
       動的計画法
             秋葉 拓哉 / (iwi)
はじめに
• 「動的計画法」は英語で
     「Dynamic Programming」
  と言います.

• 略して「DP」とよく呼ばれます.

• スライドでも以後使います.
全探索と DP の関係

動的計画法のアイディア
ナップサック問題とは?
• n 個の品物がある
• 品物 i は重さ wi, 価値 vi
• 重さの合計が U を超えないように選ぶ
 – 1 つの品物は 1 つまで
• この時の価値の合計の最大値は?

     品物 1    品物 2          品物 n
     重さ w1   重さ w2   ・・・   重さ wn
     価値 v1   価値 v2         価値 vn
ナップサック問題の例
        品物 1     品物 2     品物 3     品物 4
U=5     w1 = 2   w2 = 1   w3 = 3   w4 = 2
        v1 = 3   v2 = 2   v3 = 4   v4 = 2




        品物 1     品物 2     品物 3     品物 4
答え 7    w1 = 2   w2 = 1   w3 = 3   w4 = 2
        v1 = 3   v2 = 2   v3 = 4   v4 = 2
全探索のアルゴリズム (1/3)
             品物 1      品物 2      品物 3      品物 4
   U = 10    w1 = 2    w2 = 2    w3 = 3    w4 = 2
             v1 = 3    v2 = 2    v3 = 4    v4 = 2



                      品物 1      品物 2      品物 3      品物 4
            U=8       w1 = 2    w2 = 2    w3 = 3    w4 = 2
                      v1 = 3    v2 = 2    v3 = 4    v4 = 2
品物 1 を
 使う


                      品物 1      品物 2      品物 3      品物 4
            U = 10    w1 = 2    w2 = 2    w3 = 3    w4 = 2
品物 1 を                v1 = 3    v2 = 2    v3 = 4    v4 = 2
使わない




         品物 1 から順に,使う場合・使わない場合の両方を試す
全探索のアルゴリズム (2/3)

// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
int search(int i, int u) {
          if (i == n) {           // もう品物は残っていない
                       return 0;
          } else if (u < w[i]) { // この品物は入らない
                       return search(i + 1, u);
          } else {                // 入れない場合と入れる場合を両方試す
                       int res1 = search(i + 1, u);
                       int res2 = search(i + 1, u - w[i]) + v[i];
                       return max(res1, res2);
          }
}



              外からは search(0, U) を呼ぶ
全探索のアルゴリズム (3/3)
// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
int search(int i, int u) {
          …
}




    このままでは,指数時間かかる
      (U が大きければ,2n 通り試してしまう)


      少しでも n が大きくなると
       まともに計算できない
改善のアイディア
// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
int search(int i, int u) {
          …
}




       大事な考察 : search(i, u) は
  i, u が同じなら常に同じ結果
同じ結果になる例

               品物 1            品物 2     品物 3     品物 4
U = 10 - 2     w1 = 2          w2 = 2   w3 = 3   w4 = 2   ・・・
               v1 = 3          v2 = 2   v3 = 4   v4 = 2




               品物 1            品物 2     品物 3     品物 4
U = 10 - 2     w1 = 2          w2 = 2   w3 = 3   w4 = 2   ・・・
               v1 = 3          v2 = 2   v3 = 4   v4 = 2




     品物 3 以降の最適な選び方は同じ
     • 2 + search(3, 10 – 2)
                                2 度全く同じ探索をしてしまう
     • 3 + search(3, 10 – 2)
動的計画法のアイディア
• 同じ探索を 2 度しないようにする

• search(i, u) を
  – 各 (i, u) について一度だけ計算
  – その値を何度も使いまわす


• 名前はいかついが,非常に簡単な話
  – 簡単な話だが,効果は高い(次)
動的計画法の計算量
• 全探索では指数時間だった
 – O(2n),N が少し大きくなるだけで計算できな
   い

• DP では,各 (i, u) について 1 度計算する
 – なので,約 N × U 回の計算で終了
 – O(NU) (擬多項式時間,厳密にはこれでも指数時間)

• N が大きくても大丈夫になった
メモ探索,漸化式

動的計画法の実装
2 つの方法
• ナップサック問題の続き
 – DP のプログラムを完成させましょう


• 以下の 2 つの方法について述べます
 1. 再帰関数のメモ化
 2. 漸化式+ループ
方法 1 : メモ化 (1/2)
// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
int search(int i, int u) {
          …
}



• 全探索の関数 search を改造する
 – はじめての (i, u) なら
   • 探索をして,その値を配列に記録

 – はじめてでない (i, u) なら
   • 記録しておいた値を返す
方法 1 : メモ化 (2/2)
bool done[MAX_N][MAX_U + 1];   // すでに計算したかどうかの記録
int memo[MAX_N][MAX_U + 1];    // 計算した値の記録

// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
int search(int i, int u) {
          if (done[i][u]) return memo[i][u]; // もう計算してた?
          int res;

        ...                    // 値を res に計算

        done[i][u] = true;     // 計算したことを記憶
        memo[i][u] = res;      // 値を記憶
        return res;
}


done を全て false に初期化し,search(0, U) を呼ぶ
方法 2 : 漸化式 (1/3)
• 全探索のプログラムを式に

                     search(i + 1, u)
search(i, u) = max
                     search(i + 1, u – wi) + vi
  (場合分けは省略)




• このような式を,漸化式と呼ぶ
 – パラメータが異なる自分自身との間の式
方法 2 : 漸化式 (2/3)
                      search(i + 1, u)
search(i, u) = max
                      search(i + 1, u – wi) + vi

• i が大きい方から計算してゆけばよい
 – 下のような表を埋めてゆくイメージ

 i \u   0     1   2   3    …          i の大きい方から
  1                                   埋めてゆく
  2
                                      埋める際に,既
  3                                   に埋めた部分の
  …                                   値を利用する
方法 2 : 漸化式 (3/3)
int dp[MAX_N + 1][MAX_U + 1];              // 埋めてゆく「表」

int do_dp() {
     for (int u = 0; u <= U; u++) dp[N][u] = 0;       // 境界条件

     for (int i = N – 1; i >= 0; i--) {
           for (int u = 0; u <= U; u++) {
                 if (u < w[i])               // u が小さく,商品 i が使えない
                       dp[i][u] = dp[i + 1][u];
                 else                        // 商品 i が使える
                       dp[i][u] = max( dp[i + 1][u] , dp[i + 1][u – w[i]] + v[i] );
           }
     }
     return dp[0][U];
}
どちらの方法を使うべきか
• 好きな方を使いましょう
 – どちらでも,多くの場合大丈夫です


• 後で,比較をします
 – どちらも使いこなせるようになるのがベスト
呼び方
• 方法 1 (再帰関数のメモ化)をメモ探索
• 方法 2 (漸化式+ループ)を動的計画法 (DP)
と呼ぶことがあります.

– 「動的計画法」と言ったとき
 • メモ探索を含む場合と含まない場合がある
 • 2 つにあまり差がない状況では区別されない
   – アルゴリズムの話としては(ほぼ)差がない
   – 書き方としての違い
Tips
• 大きすぎる配列をローカル変数として確
  保しないこと
 – 大きな配列はグローバルに取る
  • スタック領域とヒープ領域
  • スタック領域の制限
 – 大丈夫な場合もあるが,多くはない(IOI 等)
知らない問題を動的計画法で解く

動的計画法の作り方
動的計画法の問題を解く
• おすすめの流れ (初心者)
    1. 全探索によるアルゴリズムを考える
    2. 動的計画法のアルゴリズムにする

• ここまでのナップサック問題の説明と同
  様の流れで解けばよい
    – パターンにしてしまおう

•   実際には,全探索を考えるのと,漸化式を考えるのは,ほぼ同じ行為
簡単な例で復習
• フィボナッチ数列
int fib(int n) {
      if (n == 0) return 0;
      if (n == 1) return 1;
      return fib(n – 1) + fib(n – 2);
}


• これを,先ほどと同様の流れで
   – メモ探索
   – 動的計画法(ループ)
に書き直してみてください.
非常に簡単ですが,やり方の確認なので,形式的に行うようにしましょう
メモ探索
bool done[MAX_N + 1];
int memo[MAX_N + 1];

int fib(int n) {
      if (n == 0) return 0;
      if (n == 1) return 1;

     if (done[n]) return memo[n];

     done[n] = true;
     return memo[n] = fib(n – 1) + fib(n- 2);
}
ループ
int dp[MAX_N + 1];

int fib(int n) {
      dp[0] = 0;
      dp[1] = 1;

     for (int i = 2; i <= n; i++) dp[i] = dp[i – 1] + dp[i – 2];

     return dp[n];
}
どんな全探索を考えれば良いのか

動的計画法にできる全探索
ナップサック問題
• ナップサック問題の際に使った全探索

// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
int search(int i, int u) {
          …
}




• これ以外にも全探索は考えられる
良くない全探索 (1/3)
// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
// そこまでに選んだ品物の価値の和が vsum
int search(int i, int u, int vsum) {
          if (i == n) {           // もう品物は残っていない
                       return vsum;
          } else if (u < w[i]) { // この品物は入らない
                       return search(i + 1, u, vsum);
          } else {                // 入れない場合と入れる場合を両方試す
                       int res1 = search(i + 1, u, vsum);
                       int res2 = search(i + 1, u - w[i], vsum + v[i]);
                       return max(res1, res2);
          }
}



            外からは search(0, U, 0) を呼ぶ
良くない全探索 (2/3)

    // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
    // そこまでに選んだ品物の価値の和が vsum
    int search(int i, int u, int vsum) {
          ...
    }



• 引数が増え,動的計画法に出来ない
     – 各 (i, u, vsum) で一度ずつ計算すれば出来るが,効率が悪い

•   このような方針で書くと枝刈りができたりするので,不自然な書き方ではないが…
同じ結果になる例 (再)

               品物 1            品物 2     品物 3     品物 4
U = 10 - 2     w1 = 2          w2 = 2   w3 = 3   w4 = 2   ・・・
               v1 = 3          v2 = 2   v3 = 4   v4 = 2




               品物 1            品物 2     品物 3     品物 4
U = 10 - 2     w1 = 2          w2 = 2   w3 = 3   w4 = 2   ・・・
               v1 = 3          v2 = 2   v3 = 4   v4 = 2




     品物 3 以降の最適な選び方は同じ
     • 2 + search(3, 10 – 2)
                                2 度全く同じ探索をしてしまう
     • 3 + search(3, 10 – 2)
良くない全探索 (3/3)
• 引数が増え,動的計画法に出来ない
 – 各 (i, u, vsum) で一度ずつ計算すれば出来るが,効率が悪い


• このようなことを防ぐため,

         全探索の関数の引数は,
         その後の探索に影響のある
          最低限のものにする

• 選び方は,残る容量にはよるが,そこまでの価値によら
  ない.なので vsum は引数にしない
その他の注意
• グローバル変数を変化させるようなこと
  はしてはいけない

• 状態をできるだけシンプルにする
 – × 「どの商品を使ったか」・・・ 2n
 – ○「今までに使った商品の重さの和」 ・・・ U

• ここで扱った事項は,アルゴリズムを考える際だけでなく,
  動的計画法のアルゴリズムをより効率的にしようとする際に
  も重要です.
DP の問題をいくつか簡単に

典型的問題
経路の数 (1/2)
• ●から ● へ移動する経路の数
 – 右か上に進める




• ある地点からの経路の数は,そこまでの経路によらない
経路の数 (2/2)
• 通れるなら
 – route(x, y) = route(x-1, y) + route(x, y-1)
• ×なら
 – route(x, y) = 0
最長増加部分列(LIS) (1/2)
• 数字の列が与えられる
• 増加する部分列で,最も長いもの

• 後ろの増加部分列は,
  一番最後に使った数
  のみよる
最長増加部分列(LIS) (2/2)
• lis(i) := i を最後に使った LIS の長さ

• lis(i) = maxj { lis(j) + 1 }
   – ただし,j < i かつ aj < ai




                                 lis(i)   1 2 2 3 3 4 4 5 4
最長共通部分列 (LCS)
• 2 つの文字列が与えられ,その両方に含ま
  れる最も長い文字列
 – X = “ABCBDAB”,Y = “BDCABA”   ⇒   “BCBA”


• (X の i 文字目以降, Y の j 文字目以降)
 で作れる共通部分列は同じ
最後に
DP に強くなるために
• 慣れるために,自分で何回かやってみま
  しょう

• 典型的な問題を知りましょう
 – ナップサック問題
  • 0-1,個数無制限
 – 最長増加部分列 (LIS)
 – 最長共通部分列 (LCS)
 – 連鎖行列積
ナップサック問題=DP? (1/2)
• ナップサック問題,ただし:
 – 商品の個数 n ≦ 20,
 – 価値 vi ≦ 109, 重さ wi ≦ 109
 – 重さの和の上限 U ≦ 109

• ナップサック問題だから DP だ!
      とは言わないように!
ナップサック問題=DP? (2/2)
• DP ・・・ O(nU) ⇒ 20 × 109
• 全探索 ・・・O(2n) ⇒ 220 ≒ 106

• 全探索の方が高速な場合もある

• DP に限らず,アルゴリズムは手段であり
  目的ではありません
  – 無理に使わない
おしまい

お疲れ様でした
補足スライド
集合を状態にする DP

ビット DP
TSP (1/2)
• 巡回セールスマン問題 (TSP)
 – n 個の都市があって,それぞれの間の距離がわかって
   います
 – 都市 1 から全部の都市に訪れ,都市 1 に戻る
 – 最短の移動距離は?

   1        1       2        1       1       2

                3                        3
        5                        5
    4               6        4               6


            2                        2
   4                3    4                   3
TSP (2/2)
• NP 困難問題なので,効率的な解法は期待
  できない

• 全探索は O(n!) 時間
 – n ≦ 10 程度まで


• DP を用いると O(n2 2n) 時間にできる
 – n ≦ 16 程度まで
TSP の DP の状態 (1/2)
• 状態は,下の 2 つの組
 – 既に訪れている街はどれか ・・・ 2n 通り
 – 今いる街はどれか ・・・ n 通り


• そこまでの順番に関わらず,その後の最適な道
  のりは等しい




    赤色:そこまでの道のり,緑色:そこからの最適な道のり
TSP の DP の状態 (2/2)
• 「既に訪れている街はどれか」(2n 通り)

• これを,ビットマスクで表現
 – i ビット目が 1 なら訪れている
 – i ビット目が 0 なら訪れていない
ビットマスクの利点
• 状態が 0 から 2n-1 にエンコードされ,そ
  のまま配列を利用できる

• 集合の包含関係が数値の大小関係
 – 集合 A, B について A ⊂ B ならば
 – ビット表現で a ≦ b
ビットマスクを用いた全探索
int N, D[30][30];   // 頂点数,距離行列

// 今頂点 v に居て,既に訪れた頂点のビットマスクが b
int tsp(int v, int b) {
      if (b == (1 << N) - 1) return D[v][0]; // 全部訪れた

     int res = INT_MAX;
     for (int w = 0; w < N; w++) {
           if (b & (1 << w)) continue;               // もう訪れた
           res = min(res, D[v][w] + tsp(w, b | (1 << w)));
     }
     return res;
}



                    外からは tsp(0, 1) を呼ぶ
動的計画法にする
int tsp(int v, int b) {
      ...
}



• 配列 memo[MAX_N][1 << MAX_N] 等を作っ
  て,tsp(v, b) の結果を記録すれば良い

• ループで記述するのも簡単
   – b は降順に回せばよい
2 つの実装方法の違い

メモ探索 VS 動的計画法
メモ探索の利点
• ループの順番を考えなくて良い
 – ツリー,DAG の問題


• 状態生成が楽になる場合がある
 – 状態が複雑な問題


• 起こり得ない状態を計算しなくてよい
動的計画法 (ループ) の利点
• メモリを節約できる場合がある
 – 今後の計算で必要になる部分のみ覚えていれ
   ば良い


• 実装が短い

• 再帰呼び出しのオーバーヘッドがない
配る DP と貰う DP
• 配る DP
 – 各場所の値を計算してゆくのではなく,各場
   所の値を他のやつに加えてゆくような DP
 – メモ探索ではできない


• 確率,期待値の問題で有用なことがある
おしまい

More Related Content

What's hot

指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門Yoichi Iwata
 
ウェーブレット木の世界
ウェーブレット木の世界ウェーブレット木の世界
ウェーブレット木の世界Preferred Networks
 
研究分野をサーベイする
研究分野をサーベイする研究分野をサーベイする
研究分野をサーベイするTakayuki Itoh
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとはTakuya Akiba
 
最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解くshindannin
 
Re永続データ構造が分からない人のためのスライド
Re永続データ構造が分からない人のためのスライドRe永続データ構造が分からない人のためのスライド
Re永続データ構造が分からない人のためのスライドMasaki Hara
 
深さ優先探索による塗りつぶし
深さ優先探索による塗りつぶし深さ優先探索による塗りつぶし
深さ優先探索による塗りつぶしAtCoder Inc.
 
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」Ken'ichi Matsui
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使うKazuhiro Suga
 
区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)
区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)
区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)Kensuke Otsuki
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話Nagisa Eto
 
最近のDeep Learning (NLP) 界隈におけるAttention事情
最近のDeep Learning (NLP) 界隈におけるAttention事情最近のDeep Learning (NLP) 界隈におけるAttention事情
最近のDeep Learning (NLP) 界隈におけるAttention事情Yuta Kikuchi
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門大樹 小倉
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~Takuya Akiba
 
最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング
最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング
最近のKaggleに学ぶテーブルデータの特徴量エンジニアリングmlm_kansai
 

What's hot (20)

指数時間アルゴリズム入門
指数時間アルゴリズム入門指数時間アルゴリズム入門
指数時間アルゴリズム入門
 
ウェーブレット木の世界
ウェーブレット木の世界ウェーブレット木の世界
ウェーブレット木の世界
 
研究分野をサーベイする
研究分野をサーベイする研究分野をサーベイする
研究分野をサーベイする
 
勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは勉強か?趣味か?人生か?―プログラミングコンテストとは
勉強か?趣味か?人生か?―プログラミングコンテストとは
 
最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く最小カットを使って「燃やす埋める問題」を解く
最小カットを使って「燃やす埋める問題」を解く
 
Binary indexed tree
Binary indexed treeBinary indexed tree
Binary indexed tree
 
最大流 (max flow)
最大流 (max flow)最大流 (max flow)
最大流 (max flow)
 
Marp Tutorial
Marp TutorialMarp Tutorial
Marp Tutorial
 
Re永続データ構造が分からない人のためのスライド
Re永続データ構造が分からない人のためのスライドRe永続データ構造が分からない人のためのスライド
Re永続データ構造が分からない人のためのスライド
 
深さ優先探索による塗りつぶし
深さ優先探索による塗りつぶし深さ優先探索による塗りつぶし
深さ優先探索による塗りつぶし
 
双対性
双対性双対性
双対性
 
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
 
DockerコンテナでGitを使う
DockerコンテナでGitを使うDockerコンテナでGitを使う
DockerコンテナでGitを使う
 
直交領域探索
直交領域探索直交領域探索
直交領域探索
 
区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)
区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)
区間分割の仕方を最適化する動的計画法 (JOI 2021 夏季セミナー)
 
Rolling Hashを殺す話
Rolling Hashを殺す話Rolling Hashを殺す話
Rolling Hashを殺す話
 
最近のDeep Learning (NLP) 界隈におけるAttention事情
最近のDeep Learning (NLP) 界隈におけるAttention事情最近のDeep Learning (NLP) 界隈におけるAttention事情
最近のDeep Learning (NLP) 界隈におけるAttention事情
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~プログラミングコンテストでのデータ構造 2 ~動的木編~
プログラミングコンテストでのデータ構造 2 ~動的木編~
 
最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング
最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング
最近のKaggleに学ぶテーブルデータの特徴量エンジニアリング
 

Similar to プログラミングコンテストでの動的計画法

Algorithm 速いアルゴリズムを書くための基礎
Algorithm 速いアルゴリズムを書くための基礎Algorithm 速いアルゴリズムを書くための基礎
Algorithm 速いアルゴリズムを書くための基礎Kenji Otsuka
 
ナンプレ解析ツール
ナンプレ解析ツールナンプレ解析ツール
ナンプレ解析ツールkstmshinshu
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門Kimikazu Kato
 
実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)
実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)
実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)AtCoder Inc.
 
Sanpo
SanpoSanpo
Sanpooupc
 
何もないところから数を作る
何もないところから数を作る何もないところから数を作る
何もないところから数を作るTaketo Sano
 
自然言語処理はじめました - Ngramを数え上げまくる
自然言語処理はじめました - Ngramを数え上げまくる自然言語処理はじめました - Ngramを数え上げまくる
自然言語処理はじめました - Ngramを数え上げまくるphyllo
 
130323 slide all
130323 slide all130323 slide all
130323 slide allikea0064
 

Similar to プログラミングコンテストでの動的計画法 (10)

WUPC2012
WUPC2012WUPC2012
WUPC2012
 
Algorithm 速いアルゴリズムを書くための基礎
Algorithm 速いアルゴリズムを書くための基礎Algorithm 速いアルゴリズムを書くための基礎
Algorithm 速いアルゴリズムを書くための基礎
 
20120127 nhn
20120127 nhn20120127 nhn
20120127 nhn
 
ナンプレ解析ツール
ナンプレ解析ツールナンプレ解析ツール
ナンプレ解析ツール
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
 
実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)
実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)
実践・最強最速のアルゴリズム勉強会 第二回講義資料(ワークスアプリケーションズ & AtCoder)
 
Sanpo
SanpoSanpo
Sanpo
 
何もないところから数を作る
何もないところから数を作る何もないところから数を作る
何もないところから数を作る
 
自然言語処理はじめました - Ngramを数え上げまくる
自然言語処理はじめました - Ngramを数え上げまくる自然言語処理はじめました - Ngramを数え上げまくる
自然言語処理はじめました - Ngramを数え上げまくる
 
130323 slide all
130323 slide all130323 slide all
130323 slide all
 

More from Takuya Akiba

分散深層学習 @ NIPS'17
分散深層学習 @ NIPS'17分散深層学習 @ NIPS'17
分散深層学習 @ NIPS'17Takuya Akiba
 
Learning Convolutional Neural Networks for Graphs
Learning Convolutional Neural Networks for GraphsLearning Convolutional Neural Networks for Graphs
Learning Convolutional Neural Networks for GraphsTakuya Akiba
 
TCO15 Algorithm Round 2C 解説
TCO15 Algorithm Round 2C 解説TCO15 Algorithm Round 2C 解説
TCO15 Algorithm Round 2C 解説Takuya Akiba
 
ACM-ICPC 世界大会 2015 問題 K "Tours" 解説
ACM-ICPC 世界大会 2015 問題 K "Tours" 解説ACM-ICPC 世界大会 2015 問題 K "Tours" 解説
ACM-ICPC 世界大会 2015 問題 K "Tours" 解説Takuya Akiba
 
大規模グラフ解析のための乱択スケッチ技法
大規模グラフ解析のための乱択スケッチ技法大規模グラフ解析のための乱択スケッチ技法
大規模グラフ解析のための乱択スケッチ技法Takuya Akiba
 
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-Takuya Akiba
 
Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5Takuya Akiba
 
平面グラフと交通ネットワークのアルゴリズム
平面グラフと交通ネットワークのアルゴリズム平面グラフと交通ネットワークのアルゴリズム
平面グラフと交通ネットワークのアルゴリズムTakuya Akiba
 
大規模ネットワークの性質と先端グラフアルゴリズム
大規模ネットワークの性質と先端グラフアルゴリズム大規模ネットワークの性質と先端グラフアルゴリズム
大規模ネットワークの性質と先端グラフアルゴリズムTakuya Akiba
 
大規模グラフアルゴリズムの最先端
大規模グラフアルゴリズムの最先端大規模グラフアルゴリズムの最先端
大規模グラフアルゴリズムの最先端Takuya Akiba
 

More from Takuya Akiba (10)

分散深層学習 @ NIPS'17
分散深層学習 @ NIPS'17分散深層学習 @ NIPS'17
分散深層学習 @ NIPS'17
 
Learning Convolutional Neural Networks for Graphs
Learning Convolutional Neural Networks for GraphsLearning Convolutional Neural Networks for Graphs
Learning Convolutional Neural Networks for Graphs
 
TCO15 Algorithm Round 2C 解説
TCO15 Algorithm Round 2C 解説TCO15 Algorithm Round 2C 解説
TCO15 Algorithm Round 2C 解説
 
ACM-ICPC 世界大会 2015 問題 K "Tours" 解説
ACM-ICPC 世界大会 2015 問題 K "Tours" 解説ACM-ICPC 世界大会 2015 問題 K "Tours" 解説
ACM-ICPC 世界大会 2015 問題 K "Tours" 解説
 
大規模グラフ解析のための乱択スケッチ技法
大規模グラフ解析のための乱択スケッチ技法大規模グラフ解析のための乱択スケッチ技法
大規模グラフ解析のための乱択スケッチ技法
 
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
乱択データ構造の最新事情 -MinHash と HyperLogLog の最近の進歩-
 
Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5Cache-Oblivious データ構造入門 @DSIRNLP#5
Cache-Oblivious データ構造入門 @DSIRNLP#5
 
平面グラフと交通ネットワークのアルゴリズム
平面グラフと交通ネットワークのアルゴリズム平面グラフと交通ネットワークのアルゴリズム
平面グラフと交通ネットワークのアルゴリズム
 
大規模ネットワークの性質と先端グラフアルゴリズム
大規模ネットワークの性質と先端グラフアルゴリズム大規模ネットワークの性質と先端グラフアルゴリズム
大規模ネットワークの性質と先端グラフアルゴリズム
 
大規模グラフアルゴリズムの最先端
大規模グラフアルゴリズムの最先端大規模グラフアルゴリズムの最先端
大規模グラフアルゴリズムの最先端
 

Recently uploaded

3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント
3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント
3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイントshu1108hina1020
 
My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」inspirehighstaff03
 
My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」inspirehighstaff03
 
My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」
My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」
My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」inspirehighstaff03
 
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」inspirehighstaff03
 
My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」inspirehighstaff03
 
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」inspirehighstaff03
 
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdfMy Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdfinspirehighstaff03
 
What I did before opening my business..pdf
What I did before opening my business..pdfWhat I did before opening my business..pdf
What I did before opening my business..pdfoganekyokoi
 
Divorce agreements in administrative work.pdf
Divorce agreements in administrative work.pdfDivorce agreements in administrative work.pdf
Divorce agreements in administrative work.pdfoganekyokoi
 
My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」inspirehighstaff03
 
International Politics I - Lecture 1
International Politics I - Lecture 1International Politics I - Lecture 1
International Politics I - Lecture 1Toru Oga
 
Establishment and operation of medical corporations.pdf
Establishment and operation of medical corporations.pdfEstablishment and operation of medical corporations.pdf
Establishment and operation of medical corporations.pdfoganekyokoi
 
My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」inspirehighstaff03
 
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slidessusere0a682
 
KARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhr
KARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhrKARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhr
KARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhrRodolfFernandez1
 
My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」
My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」
My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」inspirehighstaff03
 
My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」inspirehighstaff03
 
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」inspirehighstaff03
 
My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」inspirehighstaff03
 

Recently uploaded (20)

3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント
3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント
3年前期 交通基盤工学 第一回 ガイダンス 交通基盤工学の概要  パワーポイント
 
My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」
 
My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」
 
My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」
My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」
My Inspire High Award 2024「なぜ、好きなことにいつかは飽きるの」
 
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
 
My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」
 
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
 
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdfMy Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
 
What I did before opening my business..pdf
What I did before opening my business..pdfWhat I did before opening my business..pdf
What I did before opening my business..pdf
 
Divorce agreements in administrative work.pdf
Divorce agreements in administrative work.pdfDivorce agreements in administrative work.pdf
Divorce agreements in administrative work.pdf
 
My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」
 
International Politics I - Lecture 1
International Politics I - Lecture 1International Politics I - Lecture 1
International Politics I - Lecture 1
 
Establishment and operation of medical corporations.pdf
Establishment and operation of medical corporations.pdfEstablishment and operation of medical corporations.pdf
Establishment and operation of medical corporations.pdf
 
My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」
 
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
 
KARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhr
KARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhrKARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhr
KARAPATANG PANTAO.pptxhrhrhrhrhrhrhrhrhr
 
My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」
My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」
My Inspire High Award 2024「世の中の流行はどのようにして生まれるのか」
 
My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」
 
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
 
My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」
 

プログラミングコンテストでの動的計画法

  • 1. 2010/03/19 代々木オリンピックセンター (情報オリンピック春合宿) プログラミングコンテストでの 動的計画法 秋葉 拓哉 / (iwi)
  • 2. はじめに • 「動的計画法」は英語で 「Dynamic Programming」 と言います. • 略して「DP」とよく呼ばれます. • スライドでも以後使います.
  • 4. ナップサック問題とは? • n 個の品物がある • 品物 i は重さ wi, 価値 vi • 重さの合計が U を超えないように選ぶ – 1 つの品物は 1 つまで • この時の価値の合計の最大値は? 品物 1 品物 2 品物 n 重さ w1 重さ w2 ・・・ 重さ wn 価値 v1 価値 v2 価値 vn
  • 5. ナップサック問題の例 品物 1 品物 2 品物 3 品物 4 U=5 w1 = 2 w2 = 1 w3 = 3 w4 = 2 v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 1 品物 2 品物 3 品物 4 答え 7 w1 = 2 w2 = 1 w3 = 3 w4 = 2 v1 = 3 v2 = 2 v3 = 4 v4 = 2
  • 6. 全探索のアルゴリズム (1/3) 品物 1 品物 2 品物 3 品物 4 U = 10 w1 = 2 w2 = 2 w3 = 3 w4 = 2 v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 1 品物 2 品物 3 品物 4 U=8 w1 = 2 w2 = 2 w3 = 3 w4 = 2 v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 1 を 使う 品物 1 品物 2 品物 3 品物 4 U = 10 w1 = 2 w2 = 2 w3 = 3 w4 = 2 品物 1 を v1 = 3 v2 = 2 v3 = 4 v4 = 2 使わない 品物 1 から順に,使う場合・使わない場合の両方を試す
  • 7. 全探索のアルゴリズム (2/3) // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ int search(int i, int u) { if (i == n) { // もう品物は残っていない return 0; } else if (u < w[i]) { // この品物は入らない return search(i + 1, u); } else { // 入れない場合と入れる場合を両方試す int res1 = search(i + 1, u); int res2 = search(i + 1, u - w[i]) + v[i]; return max(res1, res2); } } 外からは search(0, U) を呼ぶ
  • 8. 全探索のアルゴリズム (3/3) // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ int search(int i, int u) { … } このままでは,指数時間かかる (U が大きければ,2n 通り試してしまう) 少しでも n が大きくなると まともに計算できない
  • 9. 改善のアイディア // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ int search(int i, int u) { … } 大事な考察 : search(i, u) は i, u が同じなら常に同じ結果
  • 10. 同じ結果になる例 品物 1 品物 2 品物 3 品物 4 U = 10 - 2 w1 = 2 w2 = 2 w3 = 3 w4 = 2 ・・・ v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 1 品物 2 品物 3 品物 4 U = 10 - 2 w1 = 2 w2 = 2 w3 = 3 w4 = 2 ・・・ v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 3 以降の最適な選び方は同じ • 2 + search(3, 10 – 2) 2 度全く同じ探索をしてしまう • 3 + search(3, 10 – 2)
  • 11. 動的計画法のアイディア • 同じ探索を 2 度しないようにする • search(i, u) を – 各 (i, u) について一度だけ計算 – その値を何度も使いまわす • 名前はいかついが,非常に簡単な話 – 簡単な話だが,効果は高い(次)
  • 12. 動的計画法の計算量 • 全探索では指数時間だった – O(2n),N が少し大きくなるだけで計算できな い • DP では,各 (i, u) について 1 度計算する – なので,約 N × U 回の計算で終了 – O(NU) (擬多項式時間,厳密にはこれでも指数時間) • N が大きくても大丈夫になった
  • 14. 2 つの方法 • ナップサック問題の続き – DP のプログラムを完成させましょう • 以下の 2 つの方法について述べます 1. 再帰関数のメモ化 2. 漸化式+ループ
  • 15. 方法 1 : メモ化 (1/2) // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ int search(int i, int u) { … } • 全探索の関数 search を改造する – はじめての (i, u) なら • 探索をして,その値を配列に記録 – はじめてでない (i, u) なら • 記録しておいた値を返す
  • 16. 方法 1 : メモ化 (2/2) bool done[MAX_N][MAX_U + 1]; // すでに計算したかどうかの記録 int memo[MAX_N][MAX_U + 1]; // 計算した値の記録 // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ int search(int i, int u) { if (done[i][u]) return memo[i][u]; // もう計算してた? int res; ... // 値を res に計算 done[i][u] = true; // 計算したことを記憶 memo[i][u] = res; // 値を記憶 return res; } done を全て false に初期化し,search(0, U) を呼ぶ
  • 17. 方法 2 : 漸化式 (1/3) • 全探索のプログラムを式に search(i + 1, u) search(i, u) = max search(i + 1, u – wi) + vi (場合分けは省略) • このような式を,漸化式と呼ぶ – パラメータが異なる自分自身との間の式
  • 18. 方法 2 : 漸化式 (2/3) search(i + 1, u) search(i, u) = max search(i + 1, u – wi) + vi • i が大きい方から計算してゆけばよい – 下のような表を埋めてゆくイメージ i \u 0 1 2 3 … i の大きい方から 1 埋めてゆく 2 埋める際に,既 3 に埋めた部分の … 値を利用する
  • 19. 方法 2 : 漸化式 (3/3) int dp[MAX_N + 1][MAX_U + 1]; // 埋めてゆく「表」 int do_dp() { for (int u = 0; u <= U; u++) dp[N][u] = 0; // 境界条件 for (int i = N – 1; i >= 0; i--) { for (int u = 0; u <= U; u++) { if (u < w[i]) // u が小さく,商品 i が使えない dp[i][u] = dp[i + 1][u]; else // 商品 i が使える dp[i][u] = max( dp[i + 1][u] , dp[i + 1][u – w[i]] + v[i] ); } } return dp[0][U]; }
  • 20. どちらの方法を使うべきか • 好きな方を使いましょう – どちらでも,多くの場合大丈夫です • 後で,比較をします – どちらも使いこなせるようになるのがベスト
  • 21. 呼び方 • 方法 1 (再帰関数のメモ化)をメモ探索 • 方法 2 (漸化式+ループ)を動的計画法 (DP) と呼ぶことがあります. – 「動的計画法」と言ったとき • メモ探索を含む場合と含まない場合がある • 2 つにあまり差がない状況では区別されない – アルゴリズムの話としては(ほぼ)差がない – 書き方としての違い
  • 22. Tips • 大きすぎる配列をローカル変数として確 保しないこと – 大きな配列はグローバルに取る • スタック領域とヒープ領域 • スタック領域の制限 – 大丈夫な場合もあるが,多くはない(IOI 等)
  • 24. 動的計画法の問題を解く • おすすめの流れ (初心者) 1. 全探索によるアルゴリズムを考える 2. 動的計画法のアルゴリズムにする • ここまでのナップサック問題の説明と同 様の流れで解けばよい – パターンにしてしまおう • 実際には,全探索を考えるのと,漸化式を考えるのは,ほぼ同じ行為
  • 25. 簡単な例で復習 • フィボナッチ数列 int fib(int n) { if (n == 0) return 0; if (n == 1) return 1; return fib(n – 1) + fib(n – 2); } • これを,先ほどと同様の流れで – メモ探索 – 動的計画法(ループ) に書き直してみてください. 非常に簡単ですが,やり方の確認なので,形式的に行うようにしましょう
  • 26. メモ探索 bool done[MAX_N + 1]; int memo[MAX_N + 1]; int fib(int n) { if (n == 0) return 0; if (n == 1) return 1; if (done[n]) return memo[n]; done[n] = true; return memo[n] = fib(n – 1) + fib(n- 2); }
  • 27. ループ int dp[MAX_N + 1]; int fib(int n) { dp[0] = 0; dp[1] = 1; for (int i = 2; i <= n; i++) dp[i] = dp[i – 1] + dp[i – 2]; return dp[n]; }
  • 29. ナップサック問題 • ナップサック問題の際に使った全探索 // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ int search(int i, int u) { … } • これ以外にも全探索は考えられる
  • 30. 良くない全探索 (1/3) // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ // そこまでに選んだ品物の価値の和が vsum int search(int i, int u, int vsum) { if (i == n) { // もう品物は残っていない return vsum; } else if (u < w[i]) { // この品物は入らない return search(i + 1, u, vsum); } else { // 入れない場合と入れる場合を両方試す int res1 = search(i + 1, u, vsum); int res2 = search(i + 1, u - w[i], vsum + v[i]); return max(res1, res2); } } 外からは search(0, U, 0) を呼ぶ
  • 31. 良くない全探索 (2/3) // i 番目以降の品物で,重さの総和が u 以下となるように選ぶ // そこまでに選んだ品物の価値の和が vsum int search(int i, int u, int vsum) { ... } • 引数が増え,動的計画法に出来ない – 各 (i, u, vsum) で一度ずつ計算すれば出来るが,効率が悪い • このような方針で書くと枝刈りができたりするので,不自然な書き方ではないが…
  • 32. 同じ結果になる例 (再) 品物 1 品物 2 品物 3 品物 4 U = 10 - 2 w1 = 2 w2 = 2 w3 = 3 w4 = 2 ・・・ v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 1 品物 2 品物 3 品物 4 U = 10 - 2 w1 = 2 w2 = 2 w3 = 3 w4 = 2 ・・・ v1 = 3 v2 = 2 v3 = 4 v4 = 2 品物 3 以降の最適な選び方は同じ • 2 + search(3, 10 – 2) 2 度全く同じ探索をしてしまう • 3 + search(3, 10 – 2)
  • 33. 良くない全探索 (3/3) • 引数が増え,動的計画法に出来ない – 各 (i, u, vsum) で一度ずつ計算すれば出来るが,効率が悪い • このようなことを防ぐため, 全探索の関数の引数は, その後の探索に影響のある 最低限のものにする • 選び方は,残る容量にはよるが,そこまでの価値によら ない.なので vsum は引数にしない
  • 34. その他の注意 • グローバル変数を変化させるようなこと はしてはいけない • 状態をできるだけシンプルにする – × 「どの商品を使ったか」・・・ 2n – ○「今までに使った商品の重さの和」 ・・・ U • ここで扱った事項は,アルゴリズムを考える際だけでなく, 動的計画法のアルゴリズムをより効率的にしようとする際に も重要です.
  • 36. 経路の数 (1/2) • ●から ● へ移動する経路の数 – 右か上に進める • ある地点からの経路の数は,そこまでの経路によらない
  • 37. 経路の数 (2/2) • 通れるなら – route(x, y) = route(x-1, y) + route(x, y-1) • ×なら – route(x, y) = 0
  • 38. 最長増加部分列(LIS) (1/2) • 数字の列が与えられる • 増加する部分列で,最も長いもの • 後ろの増加部分列は, 一番最後に使った数 のみよる
  • 39. 最長増加部分列(LIS) (2/2) • lis(i) := i を最後に使った LIS の長さ • lis(i) = maxj { lis(j) + 1 } – ただし,j < i かつ aj < ai lis(i) 1 2 2 3 3 4 4 5 4
  • 40. 最長共通部分列 (LCS) • 2 つの文字列が与えられ,その両方に含ま れる最も長い文字列 – X = “ABCBDAB”,Y = “BDCABA” ⇒ “BCBA” • (X の i 文字目以降, Y の j 文字目以降) で作れる共通部分列は同じ
  • 42. DP に強くなるために • 慣れるために,自分で何回かやってみま しょう • 典型的な問題を知りましょう – ナップサック問題 • 0-1,個数無制限 – 最長増加部分列 (LIS) – 最長共通部分列 (LCS) – 連鎖行列積
  • 43. ナップサック問題=DP? (1/2) • ナップサック問題,ただし: – 商品の個数 n ≦ 20, – 価値 vi ≦ 109, 重さ wi ≦ 109 – 重さの和の上限 U ≦ 109 • ナップサック問題だから DP だ! とは言わないように!
  • 44. ナップサック問題=DP? (2/2) • DP ・・・ O(nU) ⇒ 20 × 109 • 全探索 ・・・O(2n) ⇒ 220 ≒ 106 • 全探索の方が高速な場合もある • DP に限らず,アルゴリズムは手段であり 目的ではありません – 無理に使わない
  • 48. TSP (1/2) • 巡回セールスマン問題 (TSP) – n 個の都市があって,それぞれの間の距離がわかって います – 都市 1 から全部の都市に訪れ,都市 1 に戻る – 最短の移動距離は? 1 1 2 1 1 2 3 3 5 5 4 6 4 6 2 2 4 3 4 3
  • 49. TSP (2/2) • NP 困難問題なので,効率的な解法は期待 できない • 全探索は O(n!) 時間 – n ≦ 10 程度まで • DP を用いると O(n2 2n) 時間にできる – n ≦ 16 程度まで
  • 50. TSP の DP の状態 (1/2) • 状態は,下の 2 つの組 – 既に訪れている街はどれか ・・・ 2n 通り – 今いる街はどれか ・・・ n 通り • そこまでの順番に関わらず,その後の最適な道 のりは等しい 赤色:そこまでの道のり,緑色:そこからの最適な道のり
  • 51. TSP の DP の状態 (2/2) • 「既に訪れている街はどれか」(2n 通り) • これを,ビットマスクで表現 – i ビット目が 1 なら訪れている – i ビット目が 0 なら訪れていない
  • 52. ビットマスクの利点 • 状態が 0 から 2n-1 にエンコードされ,そ のまま配列を利用できる • 集合の包含関係が数値の大小関係 – 集合 A, B について A ⊂ B ならば – ビット表現で a ≦ b
  • 53. ビットマスクを用いた全探索 int N, D[30][30]; // 頂点数,距離行列 // 今頂点 v に居て,既に訪れた頂点のビットマスクが b int tsp(int v, int b) { if (b == (1 << N) - 1) return D[v][0]; // 全部訪れた int res = INT_MAX; for (int w = 0; w < N; w++) { if (b & (1 << w)) continue; // もう訪れた res = min(res, D[v][w] + tsp(w, b | (1 << w))); } return res; } 外からは tsp(0, 1) を呼ぶ
  • 54. 動的計画法にする int tsp(int v, int b) { ... } • 配列 memo[MAX_N][1 << MAX_N] 等を作っ て,tsp(v, b) の結果を記録すれば良い • ループで記述するのも簡単 – b は降順に回せばよい
  • 56. メモ探索の利点 • ループの順番を考えなくて良い – ツリー,DAG の問題 • 状態生成が楽になる場合がある – 状態が複雑な問題 • 起こり得ない状態を計算しなくてよい
  • 57. 動的計画法 (ループ) の利点 • メモリを節約できる場合がある – 今後の計算で必要になる部分のみ覚えていれ ば良い • 実装が短い • 再帰呼び出しのオーバーヘッドがない
  • 58. 配る DP と貰う DP • 配る DP – 各場所の値を計算してゆくのではなく,各場 所の値を他のやつに加えてゆくような DP – メモ探索ではできない • 確率,期待値の問題で有用なことがある