放球问题在组合数学中是一个经典问题,在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];
}
}
二、 球相同,盒相同,不允许空盒
由于要求没有空盒,我们先在每个盒子里放一个球即可,剩下(n-m)个球可以随意放,问题就转化为了有(n-m)个球,允许空盒,有多少种情况,容易发现这就是上面的dp[n-m][m]。
三、 球相同,盒不相同,不允许空盒
用隔板法即可解决:球之间有(n-1)个空,由于要分成m份,所以应该插(m-1)个隔板,所以方案数为C(n-1,m-1)。
四、 球相同,盒不相同,允许空盒
第一类斯特林数
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。