一、前言
参考文献:代码随想录
今天的主题是复习01背包加上了解多重背包;
二、单词拆分
1、思路:
这个题目的dp数组是第一次见:bool类型;
因为返回值是bool类型,然后背包的大小和物品也有些抽象,所以我们需要更具抽象思维;
dp五部曲
(1)dp数组的创建:
vector<bool> dp(s.size() + 1, false);
这里dp的含义是:在从0到i的字符串下,dict是否能组成该字符串;
(2)初始化:
dp[0] = true;
空字符串能够被dict组成 ;
(3)遍历顺序:
for (int i = 1; i < s.size() + 1; i++) {
for (auto k : wordDict) {
if (i >= k.size() &&s.substr(i - k.size(), k.size()) == k && dp[i - k.size()] == true) {
dp[i] = true;
break; // 找到就返回
}
}
}
外层遍历的是“背包”的大小,内层遍历的是物品,而且只要找到匹配合适就直推出内层循环,便可以实现重复使用;
(4)递推公式:
dp[i] = true;
很简单,但是整体理解起来就比较抽象了;
2、整体代码如下:
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
// 1、创建一个dp数组
// 这里dp的含义是:在从0到i的字符串下,dict是否能组成该字符串
vector<bool> dp(s.size() + 1, false);
// 2、初始化
dp[0] = true; // 空字符串能够被dict组成
// 3、遍历顺序
for (int i = 1; i < s.size() + 1; i++) {
for (auto k : wordDict) {
if (i >= k.size() &&s.substr(i - k.size(), k.size()) == k && dp[i - k.size()] == true) {
dp[i] = true;
break; // 找到就返回
}
}
}
// 5、打印
return dp[s.size()];
}
};
三、多重背包
1、思路:
与01背包差不多,多重背包的含义就是有n种物品,每个物品可以使用m次,这就构成了多重背包;
直接给出代码
2、代码:
#include<iostream>
#include<vector>
using namespace std;
int main() {
int C; // 最大容量
int N; // 种类
cin >> C >> N;
vector<int> w(N); // 重量
vector<int> v(N); // 价值
vector<int> k(N); // 数量
for (int i = 0; i < N; i++) {
cin >> w[i];
}
for (int i = 0; i < N; i++) {
cin >> v[i];
}
for (int i = 0; i < N; i++) {
cin >> k[i];
}
vector<int> dp(C + 1, 0);
for (int i = 0; i < N; i++) {
for (int j = C; j >= w[i]; j--) {
for (int p = 1; p <= k[i] && (j - p * w[i]) >= 0; p++) {
dp[j] = max(dp[j], dp[j - w[i] * p] + p * v[i]);
}
}
}
// for (auto i : dp) {
// cout << i << " ";
// }
// cout << endl;
cout << dp[C] << endl;
return 0;
}
最大的区别就是有了第三层遍历物品多次的循环,来达到重复使用的目的;
time to study : 2h
leave message:
Whatever you do, do it a hundred percent.
竭尽所能,力求极致。