【力扣】分割等和子集(不太像01背包的01背包)

题目描述

image

分析

出题人肯定是要尽量避免太直接的模版套用
像这题一样,挖了很多坑。
首先是题目很难让人第一时间联想到01背包
这道题换一种描述方法就是找到一个子集,使子集的元素值总和刚好等于原集合之和的一半。
也就是说是一个背包容量为sum/2的01背包问题
另外,化解为这样之后你又会发现和写的和前面的模板题又不一样,因为这道题的求解并不是装进物品的最大价值,而是使背包刚好装满。
这样的话dp数组的元素就不是物品价值,而是装进物品的重量
于是得到dp数组的长度为sum+1
而且有递推公式为:

dp[j] = max( dp[j], dp[j - weight[i]] + weight[i] )

得到代码如下:

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        if(nums.size() == 1 ||(nums.size() == 2 && nums[0] != nums[1])){
            return false;
        }
        int sum = accumulate(nums.begin(),nums.end(),0);
        if(sum%2){
            return false;
        }
        sum/=2;
        //到这里就变成了一个背包容量为sum的01背包问题
        vector<int> dp(sum+1,0);
        for(int i = 0; i < nums.size(); i++){
            for(int j = sum; j >= nums[i]; j--){
                dp[j] = max(dp[j],dp[j-nums[i]]+nums[i]);
                if(dp[j] == sum){
                    return true;
                }
            }
        }
        return false;
    }
};

后记

不能死板地套用模版,而是要理解清楚动态规划的原理,把分析五步骤和数组的设置原理搞清楚
image
image
image
image

image

posted @ 2024-03-14 20:39  SaTsuki26681534  阅读(3)  评论(0编辑  收藏  举报