n个各不相同球放入m个相同的盒子里,球全部放完后,要求最后没有空盒!求不同的放法总数。
输入一行两个数n和mn表示球数,m表示盒子数
(0<n≤20)(0≤m≤20)输出不同且合理的放法总数
样例输入
3 2样例输出
3提示 递推
第二类stirling数
解题思路
注意观察题目要求,盒子是一样的,球是不一样的,所以无论球放在哪个盒子都是一样的,但是不一样的是球要和那些球放在同一个盒子里还是它自己在一个盒子里。
本题递推式比较简单,首先可以想到一共分为一下四种情况:
1.m=0;
当盒子数为0时,显然放法为0。(没有盒子怎么放球嘛)
2.m=1;
当盒子数为1时,所有的球肯定要放在这一个盒子里面,所以方法为1。
3.m=n;
题目要求最后不能有空盒子,所以当球的个数和盒子的个数相等时,每一个盒子放一个球刚好把这些球平分,所以方法为1。
4.m<n;(这时比较复杂,耐心看下面)
当盒子的数小于球的个数时,说明一定有一个或多个盒子中要放多个球。这时我们就要找递推公式了。当盒子数为m,球数为n-1时,设此时的放法为f(n-1)(m);好,那现在增加一个球,球数变为n,那增加的这个球要放在哪里呢?仔细想一下,在没有放置增加的这个球时是不是每个盒子里面都有球?增加的这个球是不是只有两种放法:
①这个球与其他球共用一个盒子:选择其中一个盒子(有m种选择),把这个球放在这个盒子里面,其它的球的放法刚才说了是f(n-1)(m),那此时的放法是不是为m*f(n-1)(m)。(我还是画画图吧,好理解些,看下面)
②这个球独占一个盒子:先选择一个盒子,把这个盒子里面的球腾空(移到其他盒子里面),然后把增加的这个球放在这个空盒子里面(这个盒子已经确定了放一个球),此时其它的n-1个球是不是要放在剩下的m-1个盒子里面?那此时的放法是不是为f(n-。1)(m-1)。
![](https://i-blog.csdnimg.cn/blog_migrate/62e43d8d9520ec5981a50107f48c4564.png)
#include<iostream>
using namespace std;
int m,n,i,j;
long long s[25][25];//定义成long long型,要不然会爆
int main()
{
cin>>n>>m;
for(i=1;i<=n;i++)
for(j=0;j<=m;j++)
if(j==0)s[i][j]=0;//盒子数为0
else if(j==1)s[i][j]=1;//盒子数为1
else if(i==j)s[i][j]=1;//盒子数等于球数
else if(i>j)s[i][j]=j*s[i-1][j]+s[i-1][j-1];//盒子数小于球数
else if(i<j)s[i][j]=0;//盒子数大于球数
cout<<s[n][m];
return 0;
}