完全背包

完全背包

n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i]每件物品有无限个(也就是可以每个物品可以多次放入背包),求解将哪些物品装入背包里物品价值总和最大。

示例1:

输入:n = 3, w = 4, weight = [1, 3, 4], value = [15, 20, 30]
输出:60

解题思路

经典动态规划问题。完全背包和01背包的不同之处在于完全背包中的每种物品有无限多个

二维数组解法

针对示例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];
    }
};

JavaScript

/**
 * @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];
}

 

 

posted @ 2022-03-05 19:42  wltree  阅读(121)  评论(0编辑  收藏  举报