背包问题可以基本上分为01背包,多重背包,完全背包,本质上都可以化为01背包来解决
01背包的递推式:dp[i][j] = Math.max(dp[i - 1][j - weight] + value[i], dp[i - 1][j])
完全背包的递推式:dp[i][j] = Math.max(dp[i][j - weight] + value, dp[i - 1][j])
多重背包的递推式:dp[i][j] = ∑(0-k)Math.max(dp[i - 1][j - k * weight] + k * value[i], dp[i - 1][j])
根据递推式的不同,01背包在空间压缩的代码中逆序生成dp,完全背包顺序生成dp,多重背包可以将k化为多个2的幂及和的差值转换为01背包,如果k足够大,也可以转换为完全背包
// 01背包
// dp[i][j] = Math.max(dp[i - 1][j - weight] + value, dp[i - 1][j])
private static void getValueOfZeroBag(int i, int k) {
for (int j = W;j >= 1;j--) {
if (k * weight[i] <= j) {
sum[j] = Math.max(sum[j], sum[j - k * weight[i]] + k * value[i]);
}
}
}
// 完全背包
// dp[i][j] = Math.max(dp[i][j - weight] + value, dp[i - 1][j])
private static void getValueOfFullBag(int i) {
for (int j = 1;j <= W;j++) {
if (weight[i] <= j) {
sum[j] = Math.max(sum[j], sum[j - weight[i]] + value[i]);
}
}
}
// 多重背包
// 递推式可以分别转换为完全背包和01背包
private static void getValueOfMultiBag(int i) {
if (weight[i] * count[i] >= W) {
// 转换为完全背包
getValueOfFullBag(i);
} else {
// 将count[i]分成多个2的幂次方及一个差值
int m = 1;
for (;m <= count[i];m *= 2) {
getValueOfZeroBag(i, m);
}
getValueOfZeroBag(i, count[i] - m / 2);
}
}