题目
给定一个有
n
个正整数的数组
- 测试输入
5 15
5 5 10 2 3 - 测试输出
4
分析1
如果针对每个数字是否选择,可以使用简单的回溯法,如果当前和等于long
型存储。
代码1
import java.util.Scanner;
public class Summary {
static long method = 0;
static void solution(int acc, int i, int sum, int[] array) {
if (acc == sum) {
++method;
} else if (acc < sum) {
if (i < array.length) {
solution(acc + array[i], i + 1, sum, array);// 选择第i个
solution(acc, i + 1, sum, array);// 不选择第i个
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum = sc.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = sc.nextInt();
}
solution(0, 0, sum, array);
System.out.println(method);
}
}
分析2
如果从后向前考虑,为了得到一个较大的
sum
的最多方案数,需要保证之前较小的
sum
的已经得到最多方案数,从而具有最优子结构。这类似于背包问题,只是背包要求装满,且求的是装进背包的方案数。定义
m[i][j]
表示从前
i
个数中选出部分数字和为
代码2
import java.util.Scanner;
public class Summary {
static void solution(int[] array, long[][] m, int sum) {
int n = array.length;
for (int i = 1; i <= sum; i++) {
m[0][i] = 0;
}
for (int i = 0; i <= n; i++) {
m[i][0] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= sum; j++) {
if (j - array[i - 1] >= 0) {
m[i][j] = m[i - 1][j] + m[i - 1][j - array[i - 1]];
} else {
m[i][j] = m[i - 1][j];
}
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum = sc.nextInt();
int[] array = new int[n];
for (int i = 0; i < n; i++) {
array[i] = sc.nextInt();
}
long[][] m = new long[n + 1][sum + 1];
solution(array, m, sum);
System.out.println(m[n][sum]);
}
}