← ブログ一覧

0/1ナップサック問題、入れる・入れないをDPで解く - AlgoNote

DP動的計画法ナップサック最適化AlgoNote

ナップサック問題とは?

0/1ナップサック問題(0/1 Knapsack)は、重さの上限が決まったバッグに、それぞれ重さと価値を持つ品物を選んで入れ、価値の合計を最大にする問題です。各品物は丸ごと入れる(1)か入れない(0)かのどちらか — 分割できません。

品物ごとに「入れる/入れない」の2択なので全探索は2ⁿに爆発します。動的計画法(DP)は重なる部分問題を表に保存しO(nW)に削減します。


状態の定義

dp[i][w] = 先頭からi個の品物まで考え、重さ上限がwのときに得られる最大価値

こう定義すると、品物を1つ多く見るとき「今の品物を入れるか」だけ決めればよいように問題が分かれます。


漸化式

i番目の品物の重さが wt、価値が v なら

  • 入れない: dp[i-1][w](上限そのまま、価値そのまま)
  • 入れる(w ≥ wt のとき): dp[i-1][w - wt] + v(入れた重さ分だけ上限を引き価値を足す)
  • dp[i][w] = max(入れない, 入れる)

2択のうち価値が大きい方を選ぶだけです。


動作原理

ステップ1. dp[0][*] = 0(品物がなければ価値0)で初期化します。

ステップ2. 品物iを1つずつ増やし、全ての重さ上限wに対し上の漸化式で表を埋めます。

ステップ3. dp[n][W] が答え(全品物・最大上限での最大価値)です。

1次元最適化: 1行 dp[w] だけ持ち、wを大きい方から小さい方へ更新すると空間がO(W)に減ります。

AlgoNoteの可視化は、表が1マスずつ埋まり「入れる/入れない」のどちらが選ばれるかをステップごとに示します。


時間計算量と空間計算量

計算量
時間O(nW)
空間O(nW) または O(W)

nは品物数、Wは重さ上限です。


例で追ってみる

品物 (重さ, 価値) = (1, 6), (2, 10), (3, 12)、上限 W=5。

  • 品物1だけ: 上限5で価値6
  • 品物1·2: (1,6)+(2,10) を両方入れ重さ3·価値16
  • 品物1·2·3: (2,10)+(3,12) → 重さ5·価値22 → 最大22

dp[3][5] = 22 が答えです。


よくあるミス

  • 1次元の更新方向: dp[w] を小さいwから更新すると同じ品物を何度も入れられます(それは「無限ナップサック」)。0/1は必ず大きいwから
  • 上限チェックの欠落: w ≥ wt のときだけ入れる分岐を適用し負のインデックスを避けます。
  • Wが巨大なとき: O(nW)が重いなら価値基準DPなど別の定義を検討します。

AlgoNoteで直接確認しましょう

各品物で「入れる」と「入れない」の価値を比べ表が埋まる過程をAlgoNoteでステップごとに確認できます。

ナップサック問題の可視化へ →

0/1ナップサック問題、入れる・入れないをDPで解く - AlgoNote - AlgoNote | 알고노트(AlgoNote)