首页 > 试题广场 >

数字和为sum的方法数

[编程题]数字和为sum的方法数
  • 热度指数:23886 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。
当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。

输入描述:
输入为两行:
第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
第二行为n个正整数A[i](32位整数),以空格隔开。


输出描述:
输出所求的方案数
示例1

输入

5 15 5 5 10 2 3

输出

4
import java.util.Arrays;
import java.util.Scanner;

public class GetTheSum {
    public static void main(String[] args) {
        //testIt();
        Scanner scanner = new Scanner(System.in);
        int i = 0;
        String[] lines = new String[2];
        while (i <= 1 && scanner.hasNextLine()) {
            lines[i] = scanner.nextLine();
            i++;
        }

        String[] nAndSum = lines[0].split("\\s+");
        int n = Integer.parseInt(nAndSum[0]);
        int sum = Integer.parseInt(nAndSum[1]);
        int[] arr = Arrays.stream(lines[1].split("\\s+")).mapToInt(Integer::parseInt).toArray();

        long count = solve(sum, arr);
        //System.out.println("sum=" + sum + ", arr=" + Arrays.toString(arr) + ", count=" + count);
        System.out.println(count);
    }

    // target: [0, 1000]
    // values.length: [1, 1000]
    public static long solve(int target, int[] values) {
        int iCount = values.length + 1;
        int jCount = target + 1;
        // dp[i][j]
        // 在 数组前i个数字 中任选组合,使得加和为j时,方案的最大个数为 dp[i][j]
        long[][] dp = new long[iCount][jCount];

        for (int j = 0; j < jCount; j++) {
            // 在 数组前1个数字 中任选组合,使得加和为j时,方案的最大个数为 dp[1][j]
            dp[1][j] = (values[0] == j) ? 1 : 0;
        }

        // 在 数组前i个数字 中任选组合
        for (int i = 2; i < iCount; i++) {
            int val = values[i - 1];
            //使得加和为j
            for (int j = 1; j < jCount; j++) {
                // 不使用i时,就可以加和为j 的方案个数
                dp[i][j] = dp[i - 1][j];

                if (j == val) {
                    // 单单 values[i - 1] 就正好形成了一种方案
                    dp[i][j] = dp[i][j] + 1;
                    // 不使用i时,可以加和为 0 的方案个数
                    long tmp = dp[i - 1][0];
                    dp[i][j] = dp[i][j] + tmp;
                } else if (j > val) {
                    // 不使用i时,可以加和为 j-values[i-1] 的方案个数
                    long tmp = dp[i - 1][j - val];
                    dp[i][j] = dp[i][j] + tmp;
                }
                // values[i - 1]本身就已经 > j  了,任何方案都无法使用 values[i - 1] 啦
                else {

                }
            }

        }
        return dp[values.length][target];
    }

    public static void testIt() {
        int sum = 15;
        int[] arr = new int[]{5, 5, 10, 2, 3};
        long count = solve(sum, arr);
        System.out.println("sum=" + sum + ", arr=" + Arrays.toString(arr) + ", count=" + count);
    }
}

发表于 2020-12-17 00:50:46 回复(0)

动态规划
设m[i][j]是前i个数 和为j的的最大组合方案数
递归公式
1 j=0 //j-a[i]为0时,表示a[i]=j,组合数为1
0 j<0
0 i<1且j!=0
M[i][j]=M[i-1][j]+M[i-1][j-a[i]] //前i-1个 和为j的最大组合数 + 前i-1个 和为 j-a[i]的最大组合数
例如 n=7 sum=8
数据为:5 1 2 4 3 2 3
得到如下矩阵
(i\j) 0 1 2 3 4 5 6 7 8
0 1 0 0 0 0 0 0 0 0
1 1 0 0 0 0 1 0 0 0
2 1 1 0 0 0 1 1 0 0
3 1 1 1 1 0 1 1 1 1
4 1 1 1 1 1 2 2 2 1
5 1 1 1 2 2 3 3 3 3
6 1 1 2 3 3 5 5 6 6
7 1 1 2 4 4 7 8 9 11
例如:m[7][9]=m[6][8]+m[6][8-3]=11
由于当前行只用到了上一行的数值,固可用二维数组存储

    public static void main(String[] args)throws Exception{
        BufferedReader br =new BufferedReader(new InputStreamReader(System.in));
        String[] strings=br.readLine().split("\\s");
        int n=Integer.parseInt(strings[0]);
        int sum=Integer.parseInt(strings[1]);
        strings=br.readLine().split("\\s");
        int[]data=new int[n];
        for(int i=0;i<n;i++){
            data[i]=Integer.valueOf(strings[i]);
        }
        dp(n,sum,data);
    }
    private static void dp(int n,int sum,int [] data){
        long[][] m=new long[2][sum+1];
        m[0][0]=1;//j=0
        m[1][0]=1;//j=0
        for(int i=1;i<=n;i++){
            for(int j=1;j<=sum;j++){
                if(j>=data[i-1]){
                    m[1][j]=m[0][j]+m[0][j-data[i-1]];
                }else {
                    m[1][j]=m[0][j];
                }
            }
//            System.out.println(Arrays.toString(m[0]));

            for(int k=0;k<=sum;k++){
                m[0][k]=m[1][k];
            }
        }
//        System.out.println(Arrays.toString(m[0]));
        System.out.println(m[0][sum]);
    }
发表于 2018-12-08 18:46:44 回复(0)
public class Main {

    static List<Integer> list=new ArrayList<>();
    static int m;
    static long sum;
    public static void main(String[] args) {
        Scanner scan=new Scanner(System.in);
        int n = scan.nextInt();
         m=scan.nextInt();
        for (int i = 0; i < n; i++) {
            //k[i]=scan.nextInt();
            int x=scan.nextInt();
            if (x<=m) {
                list.add(x);
            }
        }
        list.add(0);
        Collections.sort(list);
        long num[][]=new long[list.size()][m+1];
        num[0][0]=1;
        for (int i = 1; i < list.size(); i++) {
            num[i][0]=1;
            for (int j = 0; j <= m; j++) {
                if (j<list.get(i)) {
                    num[i][j]=num[i-1][j];
                }
                else{
                    num[i][j]=num[i-1][j]+num[i-1][j-list.get(i)];
                }
            }
        }
        System.out.println(num[list.size()-1][m]);
    }
}

发表于 2018-10-01 17:08:37 回复(0)
import java.util.Scanner;

public class Main {
    public static long numberOfMethod(int[] A, int sum){
        long[] dp = new long[sum + 1]; //这里用long类型,用int只能80%
        dp[0] = 1;
        for (int i : A){
            for (int j = sum; j >= i; j--){
                dp[j] += dp[j - i];
            }
        }
        return dp[sum];
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()){
            int n = sc.nextInt();
            int sum = sc.nextInt();
            int[] A = new int[n];
            for (int i = 0; i < n; i++){
                A[i] = sc.nextInt();
            }            
            System.out.println(numberOfMethod(A, sum));
        }
        sc.close();
    }
}
发表于 2018-03-20 17:18:41 回复(0)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int sum = scanner.nextInt();
        int[] arr = new int[n+1];
        for (int i = 1; i <= n; i++) {
            arr[i] = scanner.nextInt();
        }

        System.out.println(calculate(arr, n, sum));
    }

    public static long calculate(int[] arr, int n, int sum) {
        long[][] dp = new long[n+1][sum + 1];
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j <= sum; j++) {
                if (j >= arr[i])
                    dp[i][j] = dp[i-1][j] + dp[i-1][j-arr[i]];
                else
                    dp[i][j] = dp[i-1][j];
            }
        }
        return dp[n][sum];
    }
}
发表于 2018-03-18 18:06:28 回复(0)
import java.util.Scanner;
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int sum = sc.nextInt();
        int[] a = new int[n+1];
        for (int i=1; i<=n; i++){
            a[i] = sc.nextInt();
        }
        System.out.println(getres(a,n,sum));
    }
    public static long getres(int[] a, int n, int sum){
        long[][] res = new long[n+1][sum+1];
        res[0][0] = 1;
        for (int i=1; i<=n; i++){
            for (int j=0; j<=sum; j++){
                if (j >= a[i])
                    res[i][j] = res[i-1][j-a[i]] + res[i-1][j];
                else
                    res[i][j] = res[i-1][j];
            }
        }
        return res[n][sum];
    }
}

res表示用前i个值组成和为j的方案个数
编辑于 2018-03-04 10:51:10 回复(0)
//不是很理解这个递推,很多人就直接写了,有没有人讲讲啊
import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        while (in.hasNext()) {
            int count = in.nextInt();
            int sum = in.nextInt();
            int[] array = new int[count+1];
            for (int i = 1; i <= count; i++)
                array[i] = in.nextInt();

            long[][] dp = new long[count + 1][sum + 1];
            for (int i = 0; i <= count; i++)
                dp[i][0] = 1;

            for (int i = 1; i <= count; i++) {
                for (int j = 0; j <= sum; j++) {
                    if (j >= array[i])
                        dp[i][j] = dp[i-1][j] + dp[i-1][j-array[i]];
                    else
                        dp[i][j] = dp[i-1][j];
                }
            }
            System.out.println(dp[count][sum]);
        }
    }
}

发表于 2017-12-25 14:33:18 回复(0)
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {

		Scanner cin = new Scanner(System.in);

		int n = cin.nextInt();
		int m = cin.nextInt();

		int arr[] = new int[n+1];
                //代表你使用前i个数组组成j的最大组合数
		long dp[][] = new long[n + 1][m + 1];
		for (int i = 1; i <= n; i++) {
			arr[i] = cin.nextInt();
		}

		
		for (int i = 0; i < m; i++) {
			dp[0][i] = 0;
		}
		//注意,你的dp[0][0]一定要是1,否则会出错
		for (int i = 0; i < n; i++) {
			dp[i][0] = 1;
		}
		
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++) {
				if (arr[i] <= j) {
					dp[i][j] = dp[i - 1][j] + dp[i - 1][j - arr[i]];
				} else {
					dp[i][j] = dp[i - 1][j];
				}
				
			}
			
		}

		System.out.println(dp[n][m]);
	}

}

发表于 2017-09-06 02:34:18 回复(0)

//01背包问题的变形:根据数组前i-1个数相加和为j来决策加上第i个数是否符合条件,
//状态转移方程为f[i][j] = f[i-1][j] + f[i-1][j-target] (j>=target)
//其中f[i][j]表示数组前i个数中相加和为j的方案数
//f[i-1][j] 表示数组前i-1个数中相加和为j的方案数
//f[i-1][j-target]表示数组前i-1个数中相加和为j-target的方案数,要求j>=target,
//否则令f[i-1][j-target]=0;
// 以数组{3,2,10,5,5},target=15为例:  
//以下表格从下往上,从左到右反映了状态的转移过程,理解了这个表格的建立过程,也就理解了01背包
// 
//  i  a[i]    1   2   3   4   5   6   7   8   9   10   11   12   13   14   15
//  4   5      0   1   1   0   3   0   2   2   0   4    0    2    2    0    4
//  3   5      0   1   1   0   2   0   1   1   0   2    0    1    1    0    2
//  2   10     0   1   1   0   1   0   0   0   0   1    0    1    1    0    1
//  1   2      0   1   1   0   1   0   0   0   0   0    0    0    0    0    0
//  0   3      0   0   1   0   0   0   0   0   0   0    0    0    0    0    0
import java.util.*;
public class Main{
    
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int target = in.nextInt();
        int[] a= new int[n];
        for(int i=0; i<n; ++i){
            a[i] = in.nextInt();
        }
        long res = dfs(a,target);
        System.out.println(res);
    }

    public static long dfs(int[] array, int target){
        long [][] dp = new long[array.length][target+1];

        //表示j-target为0时,方案数加1
        for (int i=0;i<array.length; ++i){
            dp[i][0] = 1;
        }

        for (int i=0; i<array.length; ++i){
            for (int j=1; j<=target; ++j){

                if (i == 0) {
                    dp[i][j] = j-array[i] == 0 ? 1 :  0;
                }else {
                    long temp = j - array[i] >= 0 ? dp[i-1][j - array[i]] : 0;
                    dp[i][j] = dp[i - 1][j] + temp;
                }
            }
        }
        return dp[array.length-1][target];
    }

}

编辑于 2017-08-23 22:59:57 回复(0)
package LineCode.Recruit2017.滴滴出行;

import java.util.Scanner;

/**
 * 给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。
 * 当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。
 */
public class 数字和为sum的方法数 {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) {

            //输入
            int n = sc.nextInt();
            int sum = sc.nextInt();
            int[] arrs = new int[n];
            for (int i = 0; i < n; i++) {
                arrs[i] = sc.nextInt();
            }

            //处理
            long [] dp = new long[sum+1];
            dp[0] = 1;
            for (int i = 0; i < n; i++) {
                for (int j = sum; j >= arrs[i] ; j--)
                    dp[j] += dp[j-arrs[i]];
            }

            //输出
            System.out.println(dp[sum]);

        }
    }
}


发表于 2017-08-15 15:30:55 回复(2)
import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int sum = sc.nextInt();
		int [] A = new int[n];
		long [] f = new long[sum+1];
		for(int i=0;i<n;i++){
			A[i] = sc.nextInt();
		}
		f[0] = 1;
		for (int i=0;i<n;i++) {
	        for (int j=sum;j>=0;j--) {
	            if(j>=A[i]) {
	                f[j] += f[j-A[i]];
	            } 
	        }
	    }
		System.out.println(f[sum]);
	}
}
编辑于 2017-05-17 08:52:45 回复(1)