https://leetcode-cn.com/problems/partition-equal-subset-sum/
这道题要我们判断这个数组能否分割为2个子集,使得两个子集的元素和相等
因此,只要找到元素和为总和的一半的子集,就找到了两个子集
因为元素和我们只能用一次,所以在这道题中我们需要使用01背包的思想
我们可以确定的条件:
1.背包的大小为所有元素之和的一半
2.背包需要放入的商品的价值为元素的数值,重量也是
3.背包正好装满的时候,说明找到了总和为元素之和一半的子集
4.背包中每一个元素不可重复放入
接着,我们就可以按照动归的规则写题目了
1.dp数组及下标的含义,dp[i]表示,容量为i的背包,可以容纳的物品价值最大为dp[i],在本题中,可以认为,dp[i]表示背包的总容量是i,所背的物品价值最大为dp[i]
2.确定递推公式
01背包的递推公式为dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
在本题中,递推公式为dp[j] = max(dp[j], dp[j - nums[i]] + nums[i])
3.dp数组如何初始化
如果题目数据为正数,则初值为0,否则取负无穷
这样可以让dp数组在赋值的过程中取最大价值,不会被初值覆盖
在本题中初值赋0就可以了
4.确定遍历顺序
如果是一维数组,那么物品遍历的for循环放在外侧,遍历背包的for循环放在内侧,且内侧for循环倒叙遍历
5.举例推动dp数组
以下为题目代码
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum=0;
vector<int>dp(10001,0);
for(int i=0;i<nums.size();i++)sum+=nums[i];
if(sum&1==1)return false;//如果sum为奇数,那么不可能
int target=sum/2;
for(int i=0;i<nums.size();i++)
{
for(int j=target;j>=nums[i];j--)//背包容量遍历
{
dp[j]=max(dp[j],dp[j-nums[i]]+nums[i]);
}
}
if(dp[target]==target)return true;
else return false;
}
};