组合数学之放球问题 【附斯特林数】


放球问题在组合数学中是一个经典问题,在ACM比赛中也经常会出现类似的题目,这里做一个归纳。

我们假定现在有n个球,要放到m个盒子中,根据情况的不同主要可以分为一下8类(这里确保n>=m)



编号 n个球是否有区别 m个盒子是否有区别 是否允许空盒
1
2
3
4
5
6
7
8


我们对这些情况逐一分析。


一、 球相同,盒相同,允许空盒


假设dp[i][j]为球相同,盒相同,允许空盒,且有i个球,j个盒子的结果。那么我们可以分成两种情况,一种是放完有空盒的情况,那么我减去一个盒子不影响结果。还有一种是每一个盒子至少有一个球,那我们可以把每个盒子里拿去一个球,那就变成了(i-j)个球,j个盒子的结果了,即dp[i-j][j],两部分相加即可构成状态转移方程。


dp[i][j]=dp[i][j-1]+dp[i-j][j];         (i>=j)

dp[i][j]=dp[i][j-1];                        (i<j)


预处理后可以O(1)查询,预处理代码见下


void init()
{
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=1;i++)
    for(int j=1;j<maxn;j++)
    {
        dp[i][j]=1;
    }
    for(int i=2;i<maxn;i++)
    for(int j=1;j<maxn;j++)
    {
        if(i>=j)
            dp[i][j]=dp[i][j-1]+dp[i-j][j];
        else dp[i][j]=dp[i][j-1];
    }
}

PS:如果(n<m),其结果与dp[n][n]相同。

二、 球相同,盒相同,不允许空盒

由于要求没有空盒,我们先在每个盒子里放一个球即可,剩下(n-m)个球可以随意放,问题就转化为了有(n-m)个球,允许空盒,有多少种情况,容易发现这就是上面的dp[n-m][m]。


三、 球相同,盒不相同,不允许空盒

用隔板法即可解决:球之间有(n-1)个空,由于要分成m份,所以应该插(m-1)个隔板,所以方案数为C(n-1,m-1)。

四、 球相同,盒不相同,允许空盒

可根据三推得:首先我们假设先在每个盒子里放一个球,然后再往任意盒中放n个球,在这个前提下,问题就转化为共有(n+m)个球,要放到m个盒子中,不允许空盒的方案数,即C(n+m-1,m-1)。

知识补充


在介绍5,6,7之前先介绍一个小知识点:斯特林数(已经了解的可以跳过这一部分)。

第一类斯特林数

S(n,m)表示将n个不同物品排成k个非空循环排列的方法数。


可以举个形象点的例子:现在有n个人要围着m张相同圆桌坐下来,要求每张桌子非空,求方案数。


我们可以这样考虑,对于最后一个人:


如果他单独坐一桌的话,结果就是剩下的(n-1)个人围着(m-1)张圆桌而坐的方案数,即S(n-1,m-1)。


如果前面(n-1)个人已经坐了m张圆桌,这(n-1)个人的方案数为S(n-1,m),那么最后一个人就要插入到他们之中,他可以被安排在第一个人或第二个人或。。。或第(n-1)个人的左边,所以这种坐法方案数为(n-1)*S(n-1,m)。 综上所述,就可以写出第一类斯特林数的状态转移方程


S(n,m)=(n-1)*S(n-1,m)+S(n-1,m-1)


第一类斯特林数的预处理代码



void init()
{
    for(int i=1; i<maxn; i++)
    {
        s[i][0]=0,s[i][i]=1;
        for(int j=1; j<i; j++)
        {
            s[i][j]=(s[i-1][j]*(i-1)+s[i-1][j-1]);
        }
    }
}


第二类斯特林数


S(n,m)表示把n个不同物品划分到m个不可区分的盒子中且没有空盒的方案数。


我们还是来考虑最后一个物品,它有两种情况


如果最后一个物品单独放到一个盒子中,那么结果就是剩下的(n-1)个物品放到(m-1)个盒子中,且盒子非的方案数,即S(n-1,m-1)。


如果前面(n-1)个物品放完后已经没有空盒,(方案共有S(n-1,m)种),那么最后一个物品可以放在任意一个中(方案共有m种),总方案数即为m*S(n-1,m)。


综上所述,就可以写出第二类斯特林数的状态转移方程


S(n,m)=m*S(n-1,m)+S(n-1,m-1)


第二类斯特林数的预处理代码


void init()
{
    for(int i=1; i<maxn; i++)
    {
        s[i][0]=0,s[i][i]=1;
        for(int j=1; j<i; j++)
        {
            s[i][j]=(s[i-1][j]*j+s[i-1][j-1]);
        }
    }
}

接下来,我们便可以利用斯特林数解决问题5,6,7了。


【PS】下面用到的均为第二类斯特林数。


五、 球不相同,盒相同,不允许空盒


根据第二类斯特林数的定义,该问题就是n个不同的物品放入m个相同的箱子中且箱子不能为空,即S(n,m)。



六、 球不相同,盒相同,允许空盒


我们只要枚举非空盒的个数(枚举范围为1~n),可以设非空盒的个数为k,那么每次枚举得到的方案数即为S(n,k),总方案数为S(n,1)+S(n,2)+...+S(n,m)。


七、 球不相同,盒不相同,不允许空盒


对比问题七,变化的是盒子从相同变成了不同。我们可以这样考虑,S(n,m)为把n个不同物品分成m份的方案数,现在由于盒子不同,我们只要给盒子排个顺序,然后对应于m份即可,排列顺序有m!种情况,故总方案数为m!*S(n,m)。

八、 球不相同,盒不相同,允许空盒


这个问题最简单了,每个球都能任意选择一个盒子去放,每个球有m种情况,故总方案数为mn






  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值