题面:
将整数 nn 分成 kk 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n=7n=7,k=3k=3,下面三种分法被认为是相同的。
1,1,51,1,5;
1,5,11,5,1;
5,1,15,1,1.
问有多少种不同的分法。
输入格式
n,kn,k (6<n≤2006<n≤200,2≤k≤62≤k≤6)
输出格式
11 个整数,即不同的分法。
输入输出样例
输入 #1
7 3
输出 #1
4
说明/提示
四种分法为:
1,1,51,1,5;
1,2,41,2,4;
1,3,31,3,3;
2,2,32,2,3.
解题思路:
1,从小到大尝试每份的值,优化枚举范围,避免 [1,1,5],[5,1,1]的重复方案
2,每个问题的求解都只依赖于两个数值,即数值 n 和要分的份数 k,彼此之间无后效性,可以尝试 BF 到 DP的优化
代码
import java.util.Scanner;
public class Main{
public static Scanner sc=new Scanner(System.in);
public static int BF(int n,int k,int cur){
//去重: 从小到大,保持递增,依次枚举
if(k==1) //最后的数值可以全部叠加在最后一个数字上
return 1;
//从小到大,枚举每一种可能组成的元素
int ans=0;
// 当 n为 0时,循环次数为 k-1,而内循环返回的ans都为0
for (int i = n; i <=cur/k ; i++) {
ans+=BF(i,k-1,cur-i);
}
return ans ;
}
public static void main(String[] args) {
int n= sc.nextInt();
int k= sc.nextInt();
int [][] dp=new int[n+10][k+10];
// dp[i][j] 表示 i 数值 分 j 份的结果
//base case , 任何数字,只分一份的话,都只有一种结果
for (int i = 1; i < n; i++) {
dp[i][1]=1;
}
for (int i = 2; i <=n ; i++) {
for(int j=2;j<=k;j++){ //从低到高选择 cur进行 “选或不选”
if(j>i) // cur ==0
dp[i][j]=0;
else //选择 1作为一份, cur
dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
}
}
System.out.println(dp[n][k]);
}
}