题目描述
将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1,1,5;
1,5,1
5,1,1.
问有多少种不同的分法。
输入输出格式
输入格式:
n,k
输出格式:
1个整数,即不同的分法。
输入输出样例
输入样例#1: 复制
7 3
输出样例#1: 复制
4
说明
四种分法为:
1,1,5;
1,2,4;
1,3,3;
2,2,3.
题解
首先感叹真的是弱。这个DP题状态转移方程真的是想不出来。直到我看到了这道题的另一个题目。。
这题其实是排列组合里的题,可以把一个数值为n的数当做n个小球,划分的份数k当做k个盒子,那么本题可以转化为“将n个小球放到k个盒子中,小球之间与盒子之间没有区别,并且最后的结果不允许空盒”
将n个小球放到k个盒子中的情况总数 =
a.至少有一个盒子只有一个小球的情况数
+b.没有一个盒子只有一个小球的情况数
扫描二维码关注公众号,回复:
4980139 查看本文章
这样进行划分是因为这种分类可以使a和b都有能写出来的表达式:
a.因为盒子不加区分,那么1的情况数与“将n-1个小球放到k-1个盒子中”的情况数一样
b.没有一个盒子只有一个小球,那么把每个盒子中拿出来一个小球,对应的是“把(n-k)个小球放到k个盒子中的情况数”
然后将上面的思路化为动态转移方程:
设f[n,k]代表将n个小球放到k个盒子中且没有空盒的情况,那么f[n,k] = f[n-1,k-1] + f[n-k,k]
而当k=1时只有1种方法(小球全部放进1个盒子)
代码
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define exp 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
int dp[205][10];
int main()
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
dp[i][1]=1;
dp[i][0]=1;
}
for(int j=2;j<=k;j++)
{
dp[1][j]=0;
dp[0][j]=0;
}
for(int i=2;i<=n;i++)
{
for(int j=2;j<=k;j++)
{
if(i>j)
dp[i][j]=dp[i-1][j-1]+dp[i-j][j];
else
dp[i][j]=dp[i-1][j-1];
}
}
printf("%d\n",dp[n][k]);
return 0;
}