Day44 动规 完全背包 LeetCode 518 377

74 阅读1分钟

完全背包理论

  • 物品有N件,求取得的最大值,
  • 标准的完全背包问题,遍历顺序无所谓,需要取多次,所以从小到大遍历,之前01为了仅取一次从大到小遍历
// 0 1背包核心,一定是先物品再背包容量,需要从大到小 
for(int i = 0; i < weight.size(); i++) { // 遍历物品
    for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

// 完全背包,先遍历物品,在遍历背包
void test_CompletePack() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;
    vector<int> dp(bagWeight + 1, 0);
    for(int i = 0; i < weight.size(); i++) { // 遍历物品
        for(int j = weight[i]; j <= bagWeight; j++) { // 遍历背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    cout << dp[bagWeight] << endl;
}
int main() {
    test_CompletePack();
}

// 完全背包,先遍历背包,再遍历物品
void test_CompletePack() {
    vector<int> weight = {1, 3, 4};
    vector<int> value = {15, 20, 30};
    int bagWeight = 4;

    vector<int> dp(bagWeight + 1, 0);

    for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量
        for(int i = 0; i < weight.size(); i++) { // 遍历物品
            if (j - weight[i] >= 0) dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }
    }
    cout << dp[bagWeight] << endl;
}
int main() {
    test_CompletePack();
}

518. 零钱兑换 II

心得

  • 慢慢感受

题解

  • 完全背包中一维数组遍历顺序没有影响,但是本题求得是方法,是组合,组合问题对于遍历顺序有要求,必须物品在前,保证,装满背包的方法递推公式都是dp[j] += dp[j - weight[i]];
  • 背包在前的话,是排列问题,对于本题不适用
class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<int> dp(amount + 1, 0); // 总和为j的方法组合有d[j]种
        dp[0] = 1;
        for (int i = 0; i < coins.size(); i++) {
            for (int j = coins[i]; j <= amount; j++) {
                dp[j] += dp[j - coins[i]];
                cout << "硬币" << coins[i] << "容量为" << j << "时的种类"  << dp[j] << endl;
            }
        }
        return dp[amount];
    }
};

377. 组合总和 Ⅳ

心得

  • 套公式基本能过,还得慢慢感受背包巧妙

题解

  • 套组合公式能过大大部分测试用例,需要考虑两数溢出
class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int> dp(target + 1, 0); // dp[i] 目标整数i时的元素组合个数
        dp[0] = 1;
        // dp[1] = 1;
        for (int j = 0; j <= target; j++) {
            for (int i = 0; i < nums.size(); i++) { // 有溢出需要判断
                if (j - nums[i] >= 0 && dp[j] < INT_MAX - dp[j - nums[i]]) dp[j] += dp[j - nums[i]];
            }
        }
        return dp[target];
    }
};