題目
現有 r 個互不相同的盒子和 n個互不相同的球,要將這 n 個球放入 r 個盒子中,且不允許有空盒子。
請求出有多少種不同的放法,兩種放法不同當且僅當存在一個球使得該球在兩種放法中放入了不同的盒子。
數據範圍:0<=r<=n<=10
思路來源
https://www.luogu.com.cn/problemnew/solution/P1287
題解
這是普及的題你敢信orz
組合數學真的菜啊orz,還好洛谷的題解比較清晰
題解1:dp[i][j]代表i個不同球j個相同盒子的方案數,第二類斯特林數,求一下n個不同球r個相同盒子的方案數,然後乘一下r個盒子的順序即可
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=10;
int n,r,fac[N],dp[N][N];
int main(){
scanf("%d%d",&n,&r);
dp[0][0]=fac[0]=1;
for(int i=1;i<=n;++i){
fac[i]=fac[i-1]*i;
for(int j=1;j<=min(i,r);++j){
dp[i][j]=dp[i-1][j-1]+j*(dp[i-1][j]);
}
}
printf("%d\n",dp[n][r]*fac[r]);
return 0;
}
題解2:dp[i][j]代表i個不同球j個不同盒子的方案數(直接做),
最後一球放入單獨一盒子(選一個位置),共j*dp[i-1][j-1]種,
最後一球共用盒子(選一個盒子),則有j*dp[i-1][j]種
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
const int N=15;
int n,r,f[N][N];//f[i][j]:i個球j個盒子的方案數
int main(){
f[0][0]=1;
scanf("%d%d",&n,&r);
rep(i,1,n){
rep(j,1,min(i,r)){
f[i][j]=j*(f[i-1][j-1]+f[i-1][j]);
}
}
printf("%d\n",f[n][r]);
return 0;
}
題解3:f[i]表示i個盒子且都放了球的方案數,
用當前所有方案(n個球放在i個盒子裏隨便放),
減去選1個盒子只在1個盒子裏放球(),...,減去選i-1個盒子只在i-1個盒子裏放球()……
最後,就只剩在i個盒子裏放球了的方案了