将整数 n n n 分成 k k k 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如: n = 7 n=7 n=7 , k = 3 k=3 k=3,下面三种分法被认为是相同的。
1 , 1 , 5 1,1,5 1,1,5 ;
1 , 5 , 1 1,5,1 1,5,1 ;
5 , 1 , 1 5,1,1 5,1,1 .
问有多少种不同的分法。
n n n , k k k ( ( ( 6 < n ≤ 200 6
1 1 1个整数,即不同的分法。
输入 #1
7 3
输出 #1
4
四种分法为:
1 , 1 , 5 1,1,5 1,1,5 ;
1 , 2 , 4 1,2,4 1,2,4 ;
1 , 3 , 3 1,3,3 1,3,3 ;
2 , 2 , 3 2,2,3 2,2,3 .
【题目来源】
N O I P 2001 NOIP 2001 NOIP2001 提高组第二题
import java.util.Scanner;
public class P1025 {
public static int n;
public static int k;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
dfs(1,0,0);
System.out.println(count);
}
public static int count = 0;
/**
*
* @param last:实现遍历递增,使遍历不重复
* @param sum:累计到当前位置的遍历和
* @param index:遍历的当前位置
*/
public static void dfs(int last,int sum,int index){
if(index == k){
if(sum == n){
count++;
}
return;
}
//剪枝的实现,因为是递增,所以后面每一个数都大于等于当前数
for(int i=last;sum+(k-index)*i<=n;i++){
dfs(i,sum+i,index+1);
}
}
import java.util.Scanner;
public class P025 {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int maxn = n+2;
int maxm = k+2;
/*
dp[i][j]:表示将i分成j份一共有多少中方法
sum[i][j]:表示将i分成1~j份的和
*/
int[][] dp = new int[maxn][maxm];
int[][] sum = new int[maxn][maxm];
for(int i=0;i<maxn;i++){
dp[i][0] = 1; //将n分成0份只有一种方法
dp[i][1] = 1; //将n分成1份也只有一种方法
if(i<=k) dp[i][i] = 1; //将n分成n份也只有一种方法
sum[i][1] = 1;
}
for(int i=2;i<maxn;i++){
//j 不可能大于 i
for(int j=2;j<=Math.min(i,maxm-1);j++){
if(i!=j){
dp[i][j] = sum[i-j][Math.min(j,i-j)]; //剩下的份数与要分的份数
}
sum[i][j] = sum[i][j-1] + dp[i][j];
}
}
System.out.println(dp[n][k]);
}
}
/*
dp[i][j]
先将i 给每个份分1 则剩下为i-j
则dp[i][j] = dp[i-j][1]+dp[i-j][2]+...+dp[i-j][k]
k = Math.min(j,i-j) j:要分成j份 i-j:还剩下i-j份
*/