动态规划(01背包和完全背包系列)
1. 背包问题总结模板
这两道题分别是动态规划中背包问题的一种,我们可以大致把背包问题分为01背包和完全背包以及组合背包问题。
1.
- 01背包问题就是:从n个物品中选取当容积达到m的时候,背包此时的价值最大。但是背包中每种物品只能选取一次
- 完全背包则是:此时从n个物品中选取当容积达到m的时候,背包的此时价值最大,但是每种物品都可以重复选取
- 组合背包(组合和排列)问题:此时我们需要对背包中的物品要考虑顺序(然而这一种才是最应该好好思考的,因为他的遍历顺序是有严格的方式的,如果我们选择了不恰当的遍历方式,这里是会报错的,对于排序问题我们应该选择先遍历容积在遍历物品,对于组合问题我们依旧选择和别的方式一样的先遍历物品在遍历,为什么要这样呢?那是因为如果我们在排序哪里依旧使用原来的遍历顺序,是会出现重复的结果的,比如说{1,5}和{5,1},在组合里面这两个结果算一个,但是在排序里面这算两个结果)
2.首先是背包分类的模板:
- 1、0/1背包:外循环nums,内循环target,target倒序且target>=nums[i];
- 2、完全背包:外循环nums,内循环target,target正序且target>=nums[i];
- 3、组合背包(考虑顺序):外循环target,内循环nums,target正序且target>=nums[i];
- 4、分组背包:这个比较特殊,需要三重循环:外循环背包bags,内部两层循环根据题目的要求转化为1,2,3三种背包类型的模板(待定)
3.问题分类的模板:
- 1、最值问题: dp[i] = max/min(dp[i], dp[i-nums]+1)或dp[i] = max/min(dp[i], dp[i-num]+nums);
- 2、存在问题(bool):dp[i]=dp[i]||dp[i-num];
- 3、组合问题:dp[i]+=dp[i-num];
2. 01背包系列题目
2.1 LintCode—01背包问题
链接:https://www.lintcode.com/problem/125/
题解:
仔细感觉就会发现其实是在填这个物品和容积所构成的一个表格(一定要对于物品和容量所开辟的表格多开一行一列,这样做的目的也是为了能够直接进行初始化),最终需要返回的是dp[n][m],也就是从前n个物品当中任意选择物品,且体积总和不超过m的最大价值。
class Solution{
public:
int backPackII(int m, vector<int> &A, vector<int> &V) {
// write your code here
int n = A.size();
vector<vector<int>> dp(n+1,vector<int>(m+1,0));
for(int i = 1;i<=n;++i)
{
for(int j = 1;j<=m;++j)
{
if(A[i-1] > j)
{
//肯定是放不下的
dp[i][j] = dp[i-1][j];
}
else
{
dp[i][j] = std::max(dp[i-1][j-A[i-1]]+V[i-1],dp[i-1][j]);
}
}
}
return dp[n][m];
}
};
2.2 LeetCode第416题—分割等和子集(存在问题)
这道题和sum和一样,如何找到这道题是一道01背包问题,是这道题的关键。
class Solution {
public:
//left - right = 0;
//left + right = sum;
//2left = sum -> left = sum/2
bool canPartition(vector<int>& nums) {
int sum = 0;
for(int& e: nums)
sum += e;
if(sum % 2 == 1)
return false;
int bigSize = sum /2;
vector<vector<int>> dp(nums.size()+