将整数 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<n≤200 6<n≤200 , 2 ≤ k ≤ 6 2≤k≤6 2≤k≤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份 */