# [494. Target Sum](https://leetcode.com/problems/target-sum/)

# 思路

这道题给了我们一个数组（元素非负），和一个目标值，要求给数组中每个数字前添加正号或负号所组成的表达式结果与目标值S相等，求有多少种情况。

假设所有元素和为sum，所有添加正号的元素的和为A，所有添加负号的元素和为B，则有`sum = A + B` 且 `S = A - B`，解方程得`A = (sum + S)/2`。
即题目转换成：从数组中选取一些元素使和恰好为`(sum + S) / 2`。可见这是一个恰好装满的01背包问题，要求所有方案数。

我在我的博客文章[动态规划之背包问题系列](https://tangshusen.me/2019/11/24/knapsack-problem/)对常见的几类背包问题做了个总结，此题的分析见5.3节，这里只给出代码。


# C++
``` C++
class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = 0;
        // for(int &num: nums) sum += num;
        sum = accumulate(nums.begin(), nums.end(), 0);
        if(S > sum || sum < -S) return 0;
        if((S + sum) & 1) return 0;
        int target = (S + sum) >> 1;
        
        vector<int>dp(target + 1, 0);
        
        dp[0] = 1;
        for(int i = 1; i <= nums.size(); i++)
            for(int j = target; j >= nums[i-1]; j--){
                dp[j] = dp[j] + dp[j - nums[i-1]];
            } 
        
        return dp[target];
    }
};
```
