揹包問題總結
阿新 • • 發佈:2020-08-19
揹包問題可以基本上分為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);
}
}