問題例
N個の品物があります。 品物には1,2,…,Nと番号が振られています。 各i(1≤i≤N) について、品物iの重さはwiで、価値はviです。太郎君は、N個の品物のうちいくつか
引用: https://atcoder.jp/contests/dp/tasks/dp_d(一部編集)
考え方
dp[i][j](i番目までの品物から重さの合計がj以下になるように選んだ時の価値の最大値)とおいて、k個まで選べるようにしてmax(dp[i][j - k * w[i]] + k * v[i], dp[i + 1][j])とすると3重ループになってしまう。
しかしよく考えると、k(k >= 1)のとき、何回も同じ計算をしていることがわかる。なぜなら、dp[i + 1][j]の計算においてk個選ぶ場合は、dp[i + 1][j - w[i]]の計算においてk - 1個選んでいるのと同じだからである。
したがって、次のような式変形ができる。(蟻本p59より引用)
dp[i + 1][j]
= max{dp[i][j - k * w[i]] + k * v[i] | 0 <= k} //0 ~ k個順番に選んで計算している
= max(dp[i][j], max{dp[i][j - k * w[i]] + k * v[i] | 1 <= k})
= max(dp[i][j], max{dp[i][(j - w[i]) - k * w[i]] + k * v[i] | 0 <= k} + v[i]) dp[i + 1][j - w[i]]のときk - 1個選んでいる
= max(dp[i][j], dp[i + 1][j - w[i]] + v[i])
(総括)dp[i + 1][j]の選び方の考え方
個数制限あり...max(dp[i][j], まだi+1個目の品物はえらんでいないはずだから、i個目までの中から重量j - w[i]以内になるようにしたときの価値の最大値 + 今回の品物の最大値)
個数制限なし...max(dp[i][j], (複数選べるため)i+1個目がすでに選ばれている可能性があるので"i + 1個目"までの中から重量j - w[i]以内になるようにしたときの価値の最大値+ 今回の品物の最大値)