P1025 数的划分

题目描述
将整数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];

0123456kn
00000000000
10111111111
20011223
000000001
k00000001

由上图可得出以下规律:

  1. 当苹果数小于盘子数时即i<j,因为每个盘子不能为空,所以对角线的左边全部为0.
  2. 处于对角线时即i=j,刚好可以每个盘子放一个。所以只有一种放法。
  3. 所以我们只需要按照递推式求出对角线右边的即可。
  4. 为什么从上到下,从左到右依次填写表格的值?因为第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;
}

扩展知识点

  1. 如果盘子可以为空,求摆放的总数?这样递推式又是什么呢?
    想明白了吗?小靓仔(女)!!!
    依据上面的规律将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

  2. 其初始值又是怎么样的呢?
    想明白了吗?小靓仔(女)!!!
    (1)第0行(除result[0][0]=1外)全部为0。
    (2)第0列全部为1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值