三十七天补打卡,出差后一直没时间做题了,今天任务稍微轻一点,来补打卡,今天做了完全背包问题,完全背包问题中:
- 先遍历物品种类再遍历背包容量是求组合数
- 先遍历背包容量再遍历物品种类是求排列数
52.卡码网【携带研究材料】
解题过程
-
多重背包与01背包的区别是,遍历背包容量的顺序变为由小到大遍历,这样在考虑单个物品时可以多次添加到背包
-
二维dp
-
初始化
-
for (int j = weight[0]; j <= v; j++) { dp[0][j] = dp[0][j - weight[0]] + value[0]; }
-
递推公式
-
for (int i = 1; i < n; i++) { for (int j = 0; j <= v; j++) { if (j >= weight[i]) { dp[i][j] = max(dp[i][j - weight[i]] + value[i], dp[i - 1][j]); } else { dp[i][j] = dp[i - 1][j]; } } }
-
-
一维dp
- 初始化为0就行
- 递推公式
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
完全背包
#include<iostream>
#include<vector>
using namespace std;
int main() {
int n, v;
cin >> n >> v;
vector<int>weight(n);
vector<int>value(n);
for (int i = 0; i < n; i++) {
cin >> weight[i] >> value[i];
}
vector<int>dp(v + 1);
for (int i = 0; i < n; i++) {
for (int j = weight[i]; j <= v; j++) {
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
cout << dp.back() << endl;
return 0;
}
518.零钱兑换Ⅱ
解题过程
- 采用完全背包思路做出来了,除了第28个测试用例,但题目说结果保证符合 32 位带符号整数,先不管
- 先遍历物品后遍历背包容量,得到的是组合数
- 先遍历背包容量后遍历物品,得到的是排列数
完全背包
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<unsigned>dp(amount + 1);
dp[0] = 1;
for (int coin : coins) {
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp.back();
}
};
377.组合总和Ⅳ
解题过程
-
完全背包问题中
-
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
完全背包
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<unsigned>dp(target + 1);
dp[0] = 1;
for (int i = 0; i <= target; i++) {
for (int num : nums) {
if (i >= num) {
dp[i] += dp[i - num];
}
}
}
return dp.back();
}
};
57.卡码网【爬楼梯】
解题过程
- 本题为完全背包问题中的求排列个数问题,先遍历背包容量,再遍历物品个数。
完全背包
#include<iostream>
#include<vector>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<int>dp(n + 1);
dp[0] = 1;
for (int i = 0; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (i >= j) dp[i] += dp[i - j];
}
}
cout << dp.back() << endl;
return 0;
}