文章链接: 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ 70. 爬楼梯 (进阶)

视频链接: 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ

题目链接: 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ 70. 爬楼梯 (进阶)


完全背包

题目:

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

与01背包的区别:

每种物品有无数件。


注意:

完全背包的物品是可以添加多次的,所以要从小到大去遍历(01背包的遍历顺序是倒序遍历)。

#include <bits/stdc++.h>
using namespace std;

void test_CompletePack(vector<int> weight, vector<int> value, int bagweight) {
    vector<int> dp(bagweight + 1, 0);
    
    for (int i = 0; i < weight.size(); i++) {
        for (int j = 0; j <= bagweight; j++) {
            if (j >= weight[i]) {
                dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
            }
        }
    }
    cout << dp[bagweight] << '\n';
}

int main() {
    int n = 0, v = 0; //  n表示物品种类,v表示背包容量
    cin >> n >> v;
    vector <int> weight;
    vector <int> value;
    for (int i = 0; i < n; i++) {
        int a, b;
        cin >> a >> b;
        weight.push_back(a);
        value.push_back(b);
    }
    test_CompletePack(weight, value, v);
    
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.


518.零钱兑换 II

思路:

同  “494. 目标和”

区别:该题是正序遍历。


注意:

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<int> dp(amount + 1, 0);
        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]]; 
            }
        }
        return dp[amount];
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.


377.组合总和 Ⅳ

思路:

与上题有区别:上题返回的是 组合 的个数(即顺序不同,无关结果);该题返回的是 排列 的个数。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int> dp(target + 1, 0);
        dp[0] = 1;
        for (int i = 0; i <= target; i++) { // 背包
            for (int j = 0; j < nums.size(); j++) { // 物品
                if (i >= nums[j] && dp[i] < INT_MAX - dp[i - nums[j]]) {
                    // C++测试用例有两个数相加超过int的数据,
                    // 所以需要在if里加上dp[i] < INT_MAX - dp[i - num]
                    dp[i] += dp[i - nums[j]];
                }
            }
        }
        return dp[target];
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.


70.爬楼梯 (进阶)

思路:

转换成背包问题:物品数组为一次可以爬的阶数,背包容量为走的台阶数,结果就是方法数。


#include<bits/stdc++.h>
using namespace std;

int main() {
    int n = 0, m = 0;
    cin >> n >> m;
    vector<int> dp(n + 1, 0);
    dp[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (i >= j) {
                dp[i] += dp[i - j];
            }
        }
    }
    cout << dp[n] << '\n';
    
    return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.