《最終幻想起源》配置需求公佈: i7-6700+GTX 1060 起步,3 月 18 日發售
有n
件物品和一個最多能背重量為w
的揹包。第i
件物品的重量是weight[i]
,得到的價值是value[i]
。每件物品有無限個(也就是可以每個物品可以多次放入揹包),求解將哪些物品裝入揹包裡物品價值總和最大。
示例1:
輸入:n = 3, w = 4, weight = [1, 3, 4], value = [15, 20, 30]
輸出:60
解題思路
經典動態規劃問題。完全揹包和
二維陣列解法
針對示例1,如果是01揹包問題,可以得到的dp陣列如下圖所示:
從上圖可以看出,dp[1][3]
是由dp[0][3]
和dp[0][0]
推匯出來的,也就是說dp[i][j]
dp[i - 1][j]
和dp[i - 1][j - weight[i]]+ value[i]
推匯出來的。從而可以得出結論在01揹包中,當前狀態只與上方和左上方的狀態有關係。
如果是完全揹包問題,可以得到的dp陣列如下圖所示:
從上圖可以看出,dp[1][3]
是由dp[0][3]
和dp[1][0]
推匯出來的,也就是說dp[i][j]
是由dp[i - 1][j]
和dp[i][j - weight[i]] + value[i]
推匯出來的。從而可以得出結論在完全揹包中,當前狀態只與上方和左方的狀態有關係。
於是,有
01揹包的遞推公式:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]]+ value[i])
完全揹包的遞推公式:
dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]]+ value[i])
對於完全揹包dp陣列的初始化,從上圖來看還是有些複雜的。這可以通過給dp陣列新增一行來解決初始化的麻煩,也就是從從沒有物品時考慮。這樣物品0的下標就從1開始了。
C++
class Solution { public: int completeBackpake(vector<int> weight, vector<int> value, int bagsize) { vector<vector<int>> dp(weight.size() + 1, vector<int>(bagsize + 1, 0)); for (int i = 1; i < weight.size() + 1; i++) { for (int j = weight[i - 1]; j < bagsize + 1; j++) { dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i - 1]] + value[i - 1]); } } return dp[weight.size()][bagsize]; } };
JavaScript
/** * @param {number[]} weight * @param {number[]} value * @param {number} bagsize */ // 二維陣列 function completeBackpack(weight, value, bagsize) { const dp = Array(weight.length + 1).fill(0).map(item => Array(bagsize + 1).fill(0)); for (let i = 1; i < weight.length + 1; i++) { for (let j = weight[i - 1]; j < bagsize + 1; j++) { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - weight[i - 1]] + value[i - 1]); } } return dp[weight.length][bagsize]; }
一維陣列解法
0-1揹包問題 和 完全揹包問題 的一維陣列解法主要是 遍歷順序不一樣。
-
用滾動陣列的方式優化0-1揹包問題時,先正序遍歷物品,再倒序遍歷揹包(必須先物品後背包)。 因為當前狀態只與上方和左上方的狀態有關係。遞推公式為
dp[j] = max(dp[j], dp[j - weight[i]]+ value[i])
-
而用滾動陣列的方式優化完全揹包問題時,先正序遍歷物品,再正序遍歷揹包(也可以先正序遍歷揹包,再正序遍歷物品)。因為當前狀態只與上方和左方的狀態有關係。遞推公式為
dp[j] = max(dp[j], dp[j - weight[i]]+ value[i])
C++
class Solution { public: int completeBackpake(vector<int> weight, vector<int> value, int bagsize) { vector<int> dp(bagsize + 1, 0); for (int i = 0; i < weight.size(); i++) { for (int j = weight[i]; j < bagsize + 1; j++) { dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); } } return dp[bagsize]; } };
/** * @param {number[]} weight * @param {number[]} value * @param {number} bagsize */ // 一維陣列 function completeBackpack(weight, value, bagsize) { const dp = Array(bagsize + 1).fill(0); for (let i = 0; i < weight.length; i++) { for (let j = weight[i]; j < bagsize + 1; j++) { dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]); } } return dp[bagsize]; }