解法一:动态规划(完全背包)
将此问题类比成完全背包问题,可以选择的数字看作物品,总和看作体积,然后进行求解。
状态定义:$f[i][j]$,表示从数字$1,…,i$中选择,总和为$j$的方案数量;
状态转移方程:$f[i][j] = f[i-1][j] + f[i][j - i]$;
特别注意边界条件,即初始化过程。
import java.util.*;
public class Main{
static int MOD = (int)1e9 + 7;
static int N = 1010;
static int[][] f = new int[N][N];
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 初始化
for(int i = 0; i <= n; i ++) f[i][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= n; j ++){
f[i][j] = f[i - 1][j] % MOD;
if(j >= i)
f[i][j] = (int)((long)f[i][j] + (long)f[i][j - i]) % MOD;
}
System.out.println(f[n][n]);
}
}
解法二:动态规划(其它)
状态定义:$f[i][j]$,表示总和为$i$,并且恰好是$j$个数的方案数量;
状态转移方程:将所有方案分成“最小值为1”和“最小值大于1”两类,则可得$f[i][j] = f[i - 1][j - 1] + f[i - j][j]$
特别注意边界条件,即初始化过程:应该初始化成$f[0][0] = 1$,而不应该初始化成$f[0][i], i = 1, 2, …, n$,因为总和为0
且恰好有i
个数明显与前面对方案的分类矛盾,故不能这样做。注意与前一种方法的初始化进行区分。
import java.util.*;
public class Main{
static int MOD = (int)1e9 + 7;
static int N = 1010;
static int[][] f = new int[N][N];
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 初始化
f[0][0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= i; j ++)
f[i][j] = (int)((long)f[i - 1][j - 1] + (long)f[i - j][j]) % MOD;
int res = 0;
for(int i = 1; i <= n; i ++){
res += f[n][i];
res %= MOD;
}
System.out.println(res);
}
}