01背包问题变体:TargetSum

在这里插入图片描述
在这里插入图片描述
这道题是01背包问题的变体,我们稍微转换一下思路。
假设num[]数组中所有的要加上+变为正数的数字和我们用Sum(P1)表示,
num[]数组中所有要加上-变为负数的数字和我们用Sum(P2)表示,则题目要求我们:

Sum(P1)-Sum(P2)=target

稍微变形一下:

2Sum(P1)=target+Sum(P1)+Sum(P2)
Sum(P1)=(target+Sum)/2

那么我们就可以转换这个题目为背包问题:
给你一个数组num[],让你从中选择几个数组,使得他们的和为(target+Sum)/2。请问可选择的组合数最多有多少?

这样就好求多了
按照背包问题的思路求解:

状态:可选的数字,要求达成的值

定义dp数组:dp[i][j]表示在前i个数字中可以凑出的和为j的组合数量

选择:每次选择装入背包或者不装入背包,则对于第i个元素,**dp[i][j]应等于不选择nums[i-1]装入背包时候的组合数量加上选择将nums[i-1]装入背包的组合数量之和。**即 dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]]

Base Case: dp[i][0]=1

Target: 求dp[n][(target+Sum)/2]

    int findTargetSumWays(vector<int>& nums, int target) 
    {
        int n=nums.size();
        int sum=0;
        for(int i=0;i<n;i++) sum+=nums[i];
        if((target+sum)%2!=0) return 0;//处理特殊情况
        
        int m=(target+sum)/2;
        if(m<0) return 0;//处理特殊情况
        
        vector<vector<int>> dp(n+1,vector<int>(m+1,0));
        for(int i=0;i<n;i++)
            dp[i][0]=1;

        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                if(j-nums[i-1]<0)//若j-nums[i-1]<0 则没有别的选择,只能选不装
                    dp[i][j]=dp[i-1][j];
                else
                    dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]];
            }
        }
                               
        return dp[n][m];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值