zoukankan      html  css  js  c++  java
  • 目标和 动态规划

    1. 题目描述

    给定一个非负整数数组,a1, a2, ..., an,和一个目标数S。现在你有两个符号+-。对于数组中的任意一个整数,你都可以从+-中选择一个符号添加在前面。
    返回可以使最终数组和为目标数S的所有添加符号的方案数。
    提示:

    • 数组非空,且长度不会超过20
    • 初始的数组的和不会超过1000
    • 保证返回的最终结果能被32位整数存下。

    示例:

    输入:nums: [1, 1, 1, 1, 1], S: 3
    输出:5
    解释:
    
    -1+1+1+1+1 = 3
    +1-1+1+1+1 = 3
    +1+1-1+1+1 = 3
    +1+1+1-1+1 = 3
    +1+1+1+1-1 = 3
    
    一共有5种方法让最终目标和为3。
    

    2. 题解

    这道题是一个常见的背包问题,我们可以用类似求解背包问题的方法来求出可能的方案数。
    我们用dp[i][j]表示用数组中的前i个元素,组成和为j的方案数。

    public int findTargetSumWays(int[] nums, int S) {
    	int[][] dp = new int[nums.length][2001];
    	dp[0][nums[0] + 1000] = 1;
    	dp[0][-nums[0] + 1000] += 1;
    	for (int i = 1; i < nums.length; i++) {
    		for (int sum = -1000; sum <= 1000; sum++) {
    			if (dp[i - 1][sum + 1000] > 0) {
    				dp[i][sum + nums[i] + 1000] += dp[i - 1][sum + 1000];
    				dp[i][sum - nums[i] + 1000] += dp[i - 1][sum + 1000];
    			}
    		}
    	}
    	return S > 1000 ? 0 : dp[nums.length - 1][S + 1000];
    }
    

    注意到数组下标不能为负数,由于题目要求数组和不超过1000,所以需要给dp[i][j]的第二维预先增加1000

    nums: [2, 1, 1, 2], S: 0为例,这里给dp[i][j]的第二维预先增加6,因为该数组和不超过6

    public int findTargetSumWays(int[] nums, int S) {
    	int[][] dp = new int[nums.length][13];
    	dp[0][nums[0] + 6] = 1;
    	dp[0][-nums[0] + 6] += 1;
    	for (int i = 1; i < nums.length; i++) {
    		for (int sum = -6; sum <= 6; sum++) {
    			if (dp[i - 1][sum + 6] > 0) {
    				dp[i][sum + nums[i] + 6] += dp[i - 1][sum + 6];
    				dp[i][sum - nums[i] + 6] += dp[i - 1][sum + 6];
    			}
    		}
    	}
    	return S > 6 ? 0 : dp[nums.length - 1][S + 6];
    }
    


    dp[0][2 + 6]表示用数组中的前0个元素,组成和为8的方案数。因为dp[i][j]的第二维预先增加6,所以实际上dp[0][2 + 6]表示用数组中的前0个元素,组成和为2的方案数。
    因此,这里dp[3][6]表示用数组中的前3个元素(包含4个元素),组成和为0的方案数,即dp[3][0 + 6]
    解释代码:
    nums[0]+nums[0]-nums[0]两种情况,接着遍历nums[1]
    由于dp[0][-2 + 6] = 1 > 0,所以dp[1][-2 + 1 + 6] += dp[0][-2 + 6]dp[1][-2 - 1 + 6] += dp[0][-2 + 6]
    接着遍历nums[2],同理,dp[2][-3 + 1 + 6] += dp[1][-3 + 6]dp[2][-1 - 1 + 6] += dp[1][-1 + 6]
    dp[2][-2 + 6]表示用数组中的前2个元素,组成和为-2的方案数为2(-2+1-1-2-1+1)。
    这里dp[2][-2 + 6]先加dp[1][-3 + 6],再加dp[1][-1 + 6],所以要用+=来累加方案数。

    参考:

  • 相关阅读:
    hdu1875(最小生成树prime)
    hdu1839(最小生成树)
    poj2739(尺取法+质数筛)
    poj2100(尺取法)
    codeforces-div2-449-B
    gym-101350M
    gym-10135I
    gym-101350H
    gym-101350D
    hdu 5569
  • 原文地址:https://www.cnblogs.com/gzhjj/p/14171494.html
Copyright © 2011-2022 走看看