题目描述
将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序)。
例如:n=7,k=3,下面三种分法被认为是相同的。
1, 1, 5
1, 5, 1
5, 1, 1
问有多少种不同的分法。
输入格式
n,k(6<n≤200,2≤k≤6)
输出格式
1个整数,即不同的分法。
输入输出样例
输入 #1
7 3
输出 #1
4
说明/提示
四种分法为:
1, 1, 5
1, 2, 4
1, 3, 3
2, 2, 3
思路分析
这道题其实就是将n个苹果放入到k个盘子中且每个盘子不能为空的问题。
温馨提示:行代表盘子数,列代表苹果数。
因为每个盘子不能为空,所以将n个苹果放到k个盘子中可以分为至少有一个盘子只有一个苹果和每个盘子至少有两个苹果这两种互不相交且覆盖了全部情况的分法。
即递推式为result[i][j]=result[i-1][j-1]+result[i][j-i];
0 | 1 | 2 | 3 | 4 | 5 | 6 | k | … | n | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2 | 0 | 0 | 1 | 1 | 2 | 2 | 3 | |||
… | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | |
k | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
由上图可得出以下规律:
- 当苹果数小于盘子数时即i<j,因为每个盘子不能为空,所以对角线的左边全部为0.
- 处于对角线时即i=j,刚好可以每个盘子放一个。所以只有一种放法。
- 所以我们只需要按照递推式求出对角线右边的即可。
- 为什么从上到下,从左到右依次填写表格的值?因为第0行、对角线及其左边的值我们都知道即其为初始值,而我们要求result[i][j]要到它上一行的值和该行该列左边的列的值,这就决定了该表的填写顺序是从上到下,从左到右的。
代码
#include <iostream>
using namespace std;
long long result[8][205];//全局变量初始值为0,行代表分为k份,列代表数是几
int main()
{
int n,k;
cin>>n>>k;//将数n分为k份
for(int i=1;i<=k;i++){
result[i][i]=1;//因为将数i分成i份,且每份不能为空只有一种分法
for(int j=i+1;j<=n;j++){
//将数j分为i份的方案数=至少有一份是1+每一份至少为2
//这里不用条件判断的原因是i从1开始i-1>=0,j=i+1即j>i等价于j-i>0,所以不会造成数组下标越界
result[i][j]=result[i-1][j-1]+result[i][j-i];
}
}
cout<<result[k][n]<<endl;
return 0;
}
扩展知识点
-
如果盘子可以为空,求摆放的总数?这样递推式又是什么呢?
想明白了吗?小靓仔(女)!!!
依据上面的规律将n个苹果放到k个盘子中(盘子可为空)可以分为至少有一个盘子为空和每个盘子至少有1个苹果这两种互不相交且覆盖了全部情况的分法。
递推式为:
result[i][j]=result[i-1][j]; j<i
result[i][j]=result[i-1][j]+result[i][j-i] j>=i -
其初始值又是怎么样的呢?
想明白了吗?小靓仔(女)!!!
(1)第0行(除result[0][0]=1外)全部为0。
(2)第0列全部为1。