题目:
有N种物品和一个容量是 V的背包。
第 i种物品最多有 si件,每件体积是 vi,价值是 wi
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。输出最大价值。
输入格式:第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N行,每行三个整数 vi, wi, si,用空格隔开,分别表示第 i种物品的体积、价值和数量。
输出格式:输出一个整数,表示最大价值。
完全背包
int[][] dp = new int[n + 1][v + 1];
dp[0][0] = 0;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= v; j++) {
for (int k = 0; k * V[i] <= j; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * V[i]] + k * W[i]);
}
}
}
多重背包
其实就是在 0-1 背包问题的基础上,增加了每件物品可以选择多次的特点(在容量允许的情况下)。
我们可以直接将 01 背包的「状态定义」拿过来用:
dp[i][j]代表考虑前 i 件物品,放入一个容量为 j 的背包可以获得的最大价值。
由于每件物品可以被选择多次,因此对于某个 dp[i][j] 而言,其值应该为以下所有可能方案中的最大值:
选择 0 件物品 的最大价值,即dp[i-1][j]
选择 1 件物品 的最大价值,即dp[i-1][j-V[i]]+W[i]
选择 2 件物品 的最大价值,即dp[i-1][j-2V[i]]+2W[i]
...
选择 s[i] 件物品 i 的最大价值,dp[i-1][j-s[i] * V[i]]+ s[i] * W[i]
由此我们可以得出「状态转移方程」为:
dp[i][j] = max(dp[i-1][j], [i-1][j-k * V[i]]+ k * W[i]),0<k<=s[i],0<k*v[i]<=j
可以发现其状态转移方程与 完全背包 完全一致,只是多了 0<k<=s[i] 的条件。
也好理解,毕竟「完全背包」不限制物品数量,「多重背包」限制物品数量。
写的二维数组代码:
int[][] dp = new int[N + 1][V + 1];
dp[0][0] = 0;
for (int i = 1; i <= N; i++) {//dp[0][...]=false 当没有物品可选择的时候肯定没办法装满背包
for (int j = 0; j <= V; j++) {//dp[...][0]=true 背包没有空间的时候,就相当于装满了
for (int k = 0; k <= s[i]; k++) {//k从0开 始则比较dp[i] [i],从1开始不对
if (j >= k * v[i]) {
dp[i][i] = Math.max(dp[i][i], dp[i - 1][j - k * v[i]] + k * W[i]);//多重背包
}
}
}