目录
一.8种球放盒子
情况 | 球(n) | 盒子(k) | 可以空/不允许空 |
I | √ | √ | √ |
II | √ | √ | × |
III | √ | × | √ |
IV | √ | × | × |
V | × | √ | √ |
VI | × | √ | × |
VII | × | × | √ |
VIII | × | × | × |
√:相同/可以空;×:不相同/不允许空;
以上是八种搁置球的要求。
我们首先来考虑第IV种情况,
1.VI不同的球放进相同的盒子里,不允许为空:
我们把表示把 n 个不同的数划分为 k个集合的方案数,要求不能为空集,写作 S ( n , k ),类似这样的数称之为第二类斯特林数(stiling)。
类似于这样的问题,如果存在‘1’这个东西,我们首先考虑对于‘1’的判断,然后分成两种没有交集且并集为全集的情况,这个也将成为我们接下来几乎所有问题的思考方式和解题思路。
这里,我们队对1’的两种情况的讨论分为:“‘1’自己独占一个盒子”以及“‘1’和其他小球共同占有一个盒子”这两种情况。显而易见,这两个情况加和就是所有情况,所以分别表示两种情况然后使用加法原理就可以得出递推式了。
显然“‘1’自己独占一个盒子”这一种情况就是S(n-1,k-1),第二种情况就是少了一个‘1’球,然后剩下的n-1个球再在k个盒子里排序,也就是S(n-1,k),接着就是‘1’将要放到这些盒子里,虽然盒子是一样的,但是里面放了球巨变的不一样的所以,‘1’一共是有k种方案放入盒子中的,乘法原理,第二种情况的式子变为kS(n-1,k-1)。
于是我们得到了第VI个问题的递推式:
然后就是要考虑和第六种情况只有盒子可空这一条不同的问题V。
2.V不同的球放进相同的盒子里,允许为空:
所有的东西和问题VI完全一样,只是因为盒子可以为空,所以我们只要将使用的i个盒子的情况进行加和,那么这个情况就解决了。
第V个问题的递推式:
然后我们再来看看第VII和第VIII个问题。
3.VII不同的球放进不同的盒子里,允许为空:
这个就完全是高中的排列组合了,每一个球有k种不同的选择,一共有n个球,然后……就没有然后了。总之,就比较简单。
第VII个问题的式子:
4.VIII不同的球放进不同的盒子里,不允许为空:
再一次类比第VI个问题,这个问题和第VI的区别只在于盒子是否有区别,也就是将盒子先排好(k!),然后再往里头放球,乘法原理。
第VII个问题的递推式:
这种题比较经典,来一道裸的例题吧。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll S(int n,int m){
if(m<=0||n<m)
return 0;
if(n==m)
return 1;
else
return S(n-1,m-1)+S(n-1, m)*m;
}
ll fac(int i){
if(i==1)
return 1;
else
return i*fac(i-1);
}
int main(){
ll n,m;
cin>>n>>m;
cout<<S(n,m)*fac(m);
return 0;
}
清晰明了。
紧接着我们来思考第IV个问题,
5.IV相同的球放进不同的盒子里,不允许为空:
这个问题我们直接可以转化为……
这个方程组中,满足
为自然数的解的组数。
那么,就有了两种思考方式:“整数拆分然后乘上k!”以及“烧饼油条问题”:
整数拆分会在第I个问题中说明,这里不赘述。
至于“烧饼油条问题”,也就是我们平常讲得“隔板法”,也就相当于把1-n个小球排成一列,在中间k-1个间隙中放置隔板(两侧不能放),隔板不能重合放置——因为要求不能有空盒子。接着这个问题就完全的转化为了组合问题,在n-1个中选择k-1个。
第IV个问题的式子:
6.III相同的球放进不同的盒子里,允许为空:
和问题IV一样,都是转化为……