139.单词拆分
文档讲解:代码随想录
视频讲解: 你的背包如何装满?| LeetCode:139.单词拆分
状态
- dp数组
dp[j] 表示一个长度为j的单词可以由数组中的单词组成即为true,否则就是false - 递推公式
当一个i>j且[j,i]这个字符串存在于数组中,且dp[j]为true那么结果就是true - 初始化
dp[0] = true 其他初始化为false - 遍历顺序
对于这道题我们应当使用求排列。因为两个单词的顺序决定了是否合理
所以先遍历背包再遍历物品 - 打印dp
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
int ssize = s.size();
//利用hash表来方便查找
unordered_set<string> wordSet(wordDict.begin(),wordDict.end());
vector<int> dp(ssize+1,0);
dp[0] = 1;
//背包:长度为j的字符串
for(int j = 1;j<=ssize;j++)
{
//物品:数组列表的单词
//用i来控制新增的长度
for(int i = 0;i<j;i++)
{
//考虑新增字符串
string word = s.substr(i,j-i);
if(wordSet.find(word) != wordSet.end() && dp[i] == 1)
{
dp[j] = 1;
}
}
}
if(dp[ssize] == 1) return true;
return false;
}
};
多重背包
文档讲解:代码随想录
视频讲解:
状态
本质上就是01背包,只不过对于每种物品的个数大于等于1,但不是无限的。
具体解决方法就是利用01背包,然后对每个物品在判断是否选择的时候,改为选取多少个。
- dp数组
dp[j] 表示容量为j的背包的最大价值 - 递推公式
对于一个物品可以选取k个,那么如果超过了容量,就是dp[j],如果没有超过容量就选择dp[j-k*weight[i]]+k*price[i];
dp[j] = max(dp[j],dp[j-k*weight[i]]+k*price[i];
- 初始化
dp[i] = 0 - 遍历顺序
01背包,所以为了避免重复选择背包需要从后向前遍历,在对于每个物品的是否选择是还需要增加一个循环判断,选取k个物品是否合适 - 打印dp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int C,N;
cin >> C >> N;
vector<int> weight(N,0);
vector<int> price(N,0);
vector<int> nums(N,0);
for(int i = 0;i<N;i++)
{
cin >> weight[i];
}
for(int i = 0;i<N;i++)
{
cin >> price[i];
}
for(int i = 0;i<N;i++)
{
cin >> nums[i];
}
vector<int> dp(C+1,0);
//转换为01背包
for(int i = 0;i<N;i++)
{
//遍历背包
for(int j = C;j>=weight[i];j--)
{
//对每个物品选择数量
for(int k = 1;k<=nums[i]&&j-k*weight[i]>=0;k++)
{
dp[j] = max(dp[j],dp[j-k*weight[i]]+k*price[i]);
}
}
}
cout << dp[C];
return 0;
}