LintCode798: Backpack VII (完全揹包問題 DP經典)
阿新 • • 發佈:2018-12-15
完全揹包問題可以視為01揹包的變形。
解法1:沒有經過優化的DP。 dp[i][j] 表示前i件物品在價值不超過j的情況下的最大重量。 若輸入為: 8 //n = money [3,2] //prices [300,160] //weight [1,6] //amounts 輸出為 640 dp[][] 為: 0 0 0 0 0 0 0 0 0 0 0 0 300 300 300 300 300 300 0 0 160 300 320 460 480 620 640 注意這裡不能用貪婪法。比如說先花3元買weight為300的物品,然後剩下5元買兩件weight為160的物品。這樣重量為620,非最優。原因是這樣會剩下1元用不上!
時間複雜度O(nW): n是所有item的總和(注意每個item可能有若干個), W是總的money數。
class Solution { public: /** * @param n: the money of you * @param prices: the price of rice[i] * @param weight: the weight of rice[i] * @param amounts: the amount of rice[i] * @return: the maximum weight */ int backPackVII(int n, vector<int> &prices, vector<int> &weight, vector<int> &amounts) { int itemCount = prices.size(); //count of items vector<vector<int>> dp(itemCount + 1, vector<int>(n + 1, 0)); //dp[i][j] means the maximum weight of first i tems with total price <= j for (int i = 1; i <= itemCount; ++i) { // i->item[i] for (int k = 1; k <=n; ++k) { dp[i][k] = dp[i - 1][k]; } for (int j = 0; j <= amounts[i - 1]; ++j) { //j-> amount[0]..amount[i-1] for (int k = 1; k <= n; ++k) { //k-> 1 .. n if (k >= j * prices[i - 1]) { dp[i][k] = max(dp[i][k], dp[i - 1][k - j * prices[i - 1]] + j * weight[i - 1]); } } } } return dp[itemCount][n]; } };
另外還要注意,上面的三層迴圈不能這樣寫: 原因是dp[i][k]被 j 迴圈和 i 迴圈改寫了,而dp[i][k]應該是獨立於 j 迴圈的。
for (int i = 1; i <= itemCount; ++i) { // i->item[i] for (int j = 0; j <= amounts[i - 1]; ++j) { //j-> amount[0]..amount[i-1] for (int k = 1; k <= n; k++) { //k-> 1 .. n dp[i][k] = dp[i - 1][k]; //應該提出去 if (k >= j * prices[i - 1]) { dp[i][k] = max(dp[i][k], dp[i - 1][k - j * prices[i - 1]] + j * weight[i - 1]); } } } }