寒假练习 1008 Putting Apples

    首先要感谢组合数学老师啊~不然还一直坑死在这题呢(一直想用组合数求解)

   题目大意是:把n个相同的苹果放入k个相同的盒子里,可以有空盒子,问有多少种方法数?

    首先分析一下这个题目的要求:

    将n各相同的苹果放入k个相同的盒子里面,问有多少种方法?

    最简单的理解就是使用斯特林数(组合数学来求解), 但是由于斯特林数求解方法没有显式公式,所以比较难写,

    具体的讨论可见http://bbs.csdn.net/topics/360143008

    那么既然放弃了组合数学的求法(一开始一直在想), 就只能使用DP的思想来求解了,假设dp[n][k] 表示将n个球放到k个盒子里的方法数

    那么就其有无空盒子来讨论

    (1)有空盒子(那么至少一个空盒),这样就要求解出来dp[n][k-1],dp[n][k-2],dp[n][k-3]....dp[n][1];

      那么这样就有很多情况了,如果这样求解的话应该会超时( 我也没有试过),所以我们只考虑递推的过程,即假设只 有一个空盒子,

     这样就可以求出有两个空盒,3个空盒的情况,递推嘛~

    (2)没有空盒(就相当于每个盒子至少放一个球),于是就相当于求dp[n-k][k],相当于已经知道每个盒子都有一个 球了,再将剩下的n-k个球放入k个盒子中

    所以动态转方程:dp[n][k] = dp[n][k-1] + dp[n-k][k];

    需要注意的就是当n<k的时候,dp[n][k] = dp[n][n];

    因为盒子是相同的,空那几个盒子是没有区别的。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int dp[maxn][maxn];
void dpsum(int n,int k)
{
     if(n==0 || k==1)  //递推的起点 
     {
         dp[n][k] = 1;
         return ;
     }
     
     if(n<k)
     {
         if(dp[n][n]==-1)  //dp[n][n]没有求算过 
         {
             dpsum(n,n);
         }
         
         dp[n][k] = dp[n][n];
         return ;
     }
     
     //表示dp[n][k-1]存在(没有越界),且没有求算过 
     if(k>=1 && dp[n][k-1]==-1)  
     {//求算dp[n][k-1] 
         dpsum(n,k-1);
     }
     //表示dp[n-k][k]存在(没有越界),且没有求算过 
     if(n>=k && dp[n-k][k]==-1)
     {//求算dp[n-k][k] 
         dpsum(n-k,k);
     }
     
     //动态转移方程  
     dp[n][k] = dp[n-k][k] + dp[n][k-1];
     return ;
}
int main()
{
    int n,k;
    memset(dp,-1,sizeof(dp));
    //因为求解的都是固定的值,所以就只需求解一次就行了
     
    while(~scanf("%d%d",&n,&k))
    {
        if(dp[n][k] == -1) //没有求算过
        {
            dpsum(n,k);
        } 
        printf("%d\n",dp[n][k]);
    }
    
    return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值