小球装箱问题八连(组合数学)
n个球不可区分,m个盒子不可区分:
盒子不可为空:dp[n][m]= dp[n-m][m]+ dp[n-1][m-1]
盒子可为空:dp[n+m][m]= dp[n][m]+ dp[n+m-1][m-1]
对于盒子不可以为空的时候:
int dp[100][100]={0}; dp[1][1]=1; for(int i=2;i<=n;i++){ for(int j=1;j<=n;j++){ dp[i][j]=dp[i-j][j]+dp[i-1][j-1]; } }
这里解释一下这个递推式,dp[i][j]的方案数中分两类一类是方案中包含1的,一类是不包含1的:
1.包含1的由于一定分解1,所以这一类的答案等价于求dp[i-1][j-1];
2.由于一定不分解出1,所以我们反向思考如果在dp[i-m][[j]的所有方案数上全部加上1,这样所有方案数不就存在1了吗?而且和还是i。
对于盒子可以为空的时候:
我们假设可以现在每个盒子里面放一个球,也就是总球数是n+m个球,放进m个盒子里面,然后我在从每个盒子里面拿走一个小球,不就是盒子可以为空的情况了吗?所以我们可以把这个问题转化为求上面式子中的dp[n+m][m]=dp[n][m]+dp[n+m-1][m-1];
n个球不可区分,m个盒子可区分:
方法:隔板法
盒子不可为空:C(n-1,m-1)
盒子可为空:C(n+m-1,m-1)
盒子不可以为空:
由于球是不可区分,盒子是可以区分,我们可以采用上述的隔板法(在高中应该学过了),n个小球有n-1个间隙,现在分成m个集合,需要插入m-1个隔板,不就是C(n-1,m-1)吗?
盒子可以为空:
同样的套路我们可以先在每个盒子里面放一个小球,需要m个,然后把问题转化为上面不可为空的情况。
n个球可区分,m个盒子不可区分:
方法:第二类斯特林数
盒子不可为空:第二类斯特林数 S[n][m]
盒子可为空:第二类斯特灵数求和 ΣS[n][m](假设一个为空,两个为空,三个为空……说白了不就是求和吗?)
第二类斯特林数的定义:表示将n个不同的元素拆分成m个集合的方案数
求第二类斯特林数的代码:
1 for(II i=0;i<N;i++){ 2 S[i][i]=1; 3 if(i>=1) S[i][0]=0; 4 for(II j=1;j<i;j++) 5 S[i][j]=(j*S[i-1][j]+S[i-1][j-1]+mod)%mod; 6 }
n个球可区分,m个盒子可区分
盒子不可为空:第二类斯特林数*阶乘数 S[n][m]*A[m]
盒子可以为空:m^n
由于盒子可以区分了,所以直接乘一个阶乘数就可以了,至于盒子可以为空的时候,每个球有m中选择,所以答案是m^n次方
其他和整数划分有关的问题:
1.将n划分成最大数不超过k的划分数(完全背包物品1-k,背包容量n)
2. 将n划分成若干奇正整数之和的划分数(完全背包物品小于n的奇数,背包容量为n)
3. 将n划分成若干不同整数之和的划分数(0-1背包物品1-n,背包容量为n)