今天补了下周末考的测试题,但是做到第三个动态规划的题就不行了,之前都还没学动态规划,今天稍微看了看,还是不太明白,但是懂了一些。
首先的话就是对于dp数组的介绍:
dp数组的含义:
dp[i][j]:[0,i]之间的物品任取放入容量为j的背包里。
不放物品i:dp[i-1][j]此时的i-1就表示[0,i-1]个物品也就是去除了i这个物品。
放物品i:dp[i-1][j-weight[i]]+value[i]
dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
一般来说用一维数组更简单,但是更晦涩难懂。
今天就学了一下动态规划的01背包,做了两道题,
第一道:416. 分割等和子集 - 力扣(LeetCode)
对于01背包相关题的话首先确定几个方向。
- 背包的体积为sum / 2
- 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
- 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
- 背包中每一个元素是不可重复放入。
如若都满足则就是01背包类的题目。对于这道题而言的话。
class Solution {
public:
bool canPartition(vector<int>& nums) {
int i,j,k,sum=0,a,b;
vector<int>dp(10001,0);
for(i=0;i<nums.size();i++)
{
sum+=nums[i];
}
int target=sum/2;
if(sum%2==1){return false;}
for(i=0;i<nums.size();i++)
for(j=target;j>=nums[i];j--)
{
dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);
}
if(dp[target]==target)return true;
return false;
}
};
其实就是依葫芦画瓢写01背包代码
对于另一道题:1049. 最后一块石头的重量 II - 力扣(LeetCode)
对于这道题的话其实也是01背包一类的题,但是这道题难得并不是01背包相关的代码,而是阅读完整道题后,不知道是使用01背包从而引起连锁反应,根本不知道怎么做。其实怎么想到是用01背包,就是想到把这一个数组分成两堆数值相似的值,再用大的去减去小的,最后得到得不就是最小值了吗。也就等同于01背包题了。
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int i,j,k,s,a,b,c,target;
int sum=0;
int n=stones.size();
vector<int>dp(15001,0);
for(i=0;i<n;i++)
{
sum+=stones[i];
}
target=sum/2;
for(i=0;i<n;i++)
for(j=target;j>=stones[i];j--)
{
dp[j]=max(dp[j],dp[j-stones[i]]+stones[i]);
}
return sum-dp[target]-dp[target];
}
};