問題描述:有n個物品,第 i 個物品的重量與價值分別爲 與 。揹包容量爲 V,試問在每個物品最多使用一次(物品必須保持完整)的情況下,如何讓揹包裝入的物品具有更大的價值總和。現有數據如下:
w = [2,3,4,5];
v = [3,4,5,6];
V = 8;
解題思路:令 表示容量爲 j 時放入前 i 個物品的最大價值。對於第 i 件物品,有兩種選擇,即放或者不放。若不放,則 ;如放,則 。因此有 。
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 >= 1; j--) {
if (w[i - 1] <= j) {
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - w[i - 1]] + v[i - 1]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[w.length][cap];
}
時間複雜度與空間複雜度均爲 。
空間優化:由以上可知,迭代過程中的第 i 行僅與前一行相關,因此可以將存儲空間可被壓縮成一維數組,即 。由於 表示的是上一行容量小於 j 的值,爲了避免數據被覆蓋,需從後往前進行計算。
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 = cap; j >= w[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
}
}
return dp[cap];
}
上一篇:揹包問題之分數揹包問題
下一篇:揹包問題之完全揹包問題