洛谷P1287 盒子与球

文章介绍了如何利用动态规划的思路解决将一定数量的球放入不同数量盒子的问题。通过创建二维数组dp[i][j]来存储球i和盒子j的放置方法数,然后通过状态转移方程dp[i][j]=j*(dp[i-1][j-1]+dp[i-1][j])逐步计算得出答案,最后给出AC代码实现。
摘要由CSDN通过智能技术生成

题面

解题:

咦?这不排列组合嘛!于是就开始用高中的知识快乐地演算……越算越不对……诶,最终与自己和解:

以我微薄的数学知识水平,无法用排列组合里的A几取几和C几取几来解决……

动态规划dp

先创建二维数组dp[i][j]来储存,有i个球、j个盒子时的放法数。

首先,不难算出,4个球3个盒子的可能数:36种,即dp[4][3]=36……

于是,我们就以4球3盒为例,推理答案得到的过程:

4个球,可以视为3个球和1个外来球,用绿竖线分割,

我们可以先把左边的3个球放入盒子,于是我们得到了剩余空盒子的可能数:

剩余1个空盒子或者没有剩余的空盒子(不可能剩余2个以上,否则无法满足每个盒子都有球)

  • 对于剩下1个空盒子的情况:

看,我们在将左边这3个球放入2个盒子的情况数,难道不就是dp[3][2]么?

而对于这1个外来球,它必须放入唯一的空盒子,

盒子的数量有3个,每一个盒子都有可能成为那个空盒子,

因此,我们还需要对dp[3][2]×3,即为剩下1空盒子的总放法数;

  • 对于无空盒子的情况:

同样,我们在将左边这3个球放入3个盒子的情况数,难道不就是dp[3][3]么?

而对于这1个外来球,它可以任选一个盒子放,即C3取1

对dp[3][3]×3,即为无空盒子的总放法数;

最后,我们把这两种情况加起来:

dp[4][3]=dp[3][3]×3+dp[3][2]×3=6×3+6×3=36!

和我们最初计算的dp[4][3]答案相同!

故,状态转移方程:dp[i][j]=j×(dp[i-1][j-1]+dp[i-1][j])

注:i为球数,j为盒子个数

AC代码奉上

#include<iostream>
#include<cmath>

using namespace std;

int n, r, ans = 1;  //n个球,r个盒子
int dp[100][100] = { 0 };   //球数、盒子数

int main()
{
    cin >> n >> r;
    for (int i = 1; i <= n; i++)
        dp[i][1] = 1;   //初始化边界

    for (int i = 2; i <= n; i++)    //球
        for (int j = 2; j <= i; j++)//盒
            dp[i][j] = j * (dp[i - 1][j - 1] + dp[i - 1][j]);

    cout << dp[n][r] << endl;
    return 0;
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
洛谷P2791是一道关于幼儿园篮的题目。题目描述如下: 在幼儿园里,小朋友们正在进行篮比赛。每个小朋友都有一个篮,他们按照顺序依次投篮。每个小朋友投篮时,可以选择将篮投给左边的小朋友或者右边的小朋友。每个小朋友投篮得分的规则如下: 1. 如果一个小朋友左右两边的小朋友都没有投篮过,那么他的得分为1; 2. 如果一个小朋友左边的小朋友投篮过,但右边的小朋友没有投篮过,那么他的得分为左边小朋友的得分加1; 3. 如果一个小朋友右边的小朋友投篮过,但左边的小朋友没有投篮过,那么他的得分为右边小朋友的得分加1; 4. 如果一个小朋友左右两边的小朋友都投篮过,那么他的得分为左边小朋友和右边小朋友得分的最大值加1。 现在给定每个小朋友投篮的顺序,请你计算每个小朋友的得分。 例如,给定投篮顺序为[1, 0, 1, 0, 1],则第一个小朋友的得分为1,第二个小朋友的得分为2,第三个小朋友的得分为1,第四个小朋友的得分为2,第五个小朋友的得分为1。 你可以通过编写程序来解决这个问题。具体的解题思路可以参考以下步骤: 1. 创建一个数组scores,用来存储每个小朋友的得分; 2. 遍历投篮顺序数组,对于每个小朋友,根据上述规则计算他的得分,并将得分存入scores数组中; 3. 最后输出scores数组即可。 希望以上解答对你有帮助!如果你还有其他问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值