問題描述:有n個物品,第 i 個物品的重量與價值分別爲 w[i] 與 v[i]。揹包容量爲 V,試問在每個物品有無限個(物品必須保持完整)的情況下,如何讓揹包裝入的物品具有更大的價值總和。現有數據如下:
w = [2,3,4,5];
v = [3,4,5,6];
V = 10;
解題思路:令 dp[i][j] 表示從編號 1~i 的物品中挑選任意數量的任意物品放入容量爲 j 的揹包中得到的最大價值,那麼有 dp[i][j]=max{dp[i−1][j−k∗w[i]]+k∗v[i]∣0≤k&k∗w[i]≤j}。根據題意,在揹包容量不變的情況下,若增加意見物品仍然無法改變揹包內的物品,那麼最大價值仍然爲 dp[i−1][j],即 dp[i][j]=dp[i−1][j]。因此有 dp[i][j]=max{dp[i−1][j],dp[i−1][j−k∗w[i]]+k∗v[i]∣0≤k&k∗w[i]≤j}。
public int knapsackProblem(int[] w, int[] v, int cap) {
int[][] dp = new int[w.length + 1][cap + 1];
for (int i = 1; i <= w.length; i++) {
for (int j = cap; j > 0; j--) {
dp[i][j] = dp[i - 1][j];
for (int k = 0; k * w[i - 1] <= j; k++) {
dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * w[i - 1]] + k * v[i - 1]);
}
}
}
return dp[w.length][cap];
}
由以上代碼可知,時間複雜度爲 O(nV2)。
時間優化:
dp[i][j]=max{dp[i−1][j],dp[i−1][j−k∗w[i]]+k∗v[i]∣0≤k&k∗w[i]≤j}
dp[i][j]=max{dp[i−1][j],max{dp[i−1][(j−w[i])−(k−1)∗w[i]]+(k−1)∗v[i]∣0≤(k−1)∗w[i]≤j}+v[i]}
dp[i][j]=max{dp[i−1][j],max{dp[i−1][(j−w[i])−k∗w[i]]+k∗v[i]∣0≤k&(k+1)∗w[i]≤j}+v[i]}
縱觀上述表達式的第二項,有
dp[i][j−w[i]]=max{dp[i−1][(j−w[i])−k∗w[i]]+k∗v[i]∣0≤k&(k+1)∗v[i]≤j}
進而 dp[i][j]=max{dp[i−1][j],dp[i][j−w[i]]+v[i]}
空間優化:
dp[i][j]=max{dp[i−1][j],dp[i][j−w[i]]+v[i]} => dp[j]=max{dp[j],dp[j−w[i]]+v[i]},j=1,2,...cap
public int knapsackProblem(int[] w, int[] v, int cap) {
int[] dp = new int[cap + 1];
for (int i = 0; i < w.length; i++) {
for (int j = 1; j <= cap; j++) {
if (w[i] <= j) {
dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
}
}
}
return dp[cap];
}
時間複雜度爲 O(nV)。
上一篇:揹包問題之0-1揹包問題
下一篇:揹包問題之多重揹包問題