Time Limit: 1 Sec Memory Limit: 128 Mb
Description
将整数 n 分成 k 份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n = 7,k = 3,下面三种分法被认为是相同的。
1 , 1 , 5
1 , 5 , 1
5 , 1 , 1
问有多少种不同的分法。
Input
n,k (6 < n ≤ 200,2 ≤ k ≤ 6)
Output
1 个整数,即不同的分法。
Sample Input
7 3
Sample Output
4
Hint
对于样例的输入输出
四种分法为:
1 , 1 , 5
1 , 2 , 4
1 , 3 , 3
2 , 2 , 3
递推
dp[i][j]
表示 i 分成 j 份。由于每份不为 0 ,则 dp[i][j] = dp[i - j][j] + dp[i - 1][j - 1]dp[i - j][j]
表示先拿出 j 个 1 放在 j 份上,保证都不为 0,再把剩下的分 j 份,即每份都大于 1dp[i - 1][j - 1]
表示第 j 份只有 1 个,剩下的 i - 1 个分配给其他的 j - 1 份,这样保证第 j 份是最少的,不会重复
代码实现
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
/*
* 不允许为空
1. k=1: dp[n][k] = 1
2. n=k: 分成k份,每份为1, dp[n][k] = 1
3. n<k: dp[n][k] = 0
4. n>k: dp[n][k] = dp[n-1][k-1] + dp[n-k][k]
* dp[n-1][k-1]:给其中一个组分配一个1,其他组继续进行分配
* dp[n-k][k]:给k个组分配一个1
*/
int dp[220][11];
int main()
{
int n, k;
memset(dp, 0, sizeof(dp));
while (scanf("%d%d", &n, &k) != EOF)
{
// TODO: 递推,dp[n][k] 为答案
dp[0][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
{
if (i < j) dp[i][j] = 0;
else if (i == j) dp[i][j] = 1;
else if (j == 1) dp[i][j] = 1;
else dp[i][j] = dp[i - j][j] + dp[i - 1][j - 1];
}
}
printf("%d\n", dp[n][k]);
}
return 0;
}