盒子放球
盒子放球问题
第一类:
将k个球放入n个不同的盒子中,每个盒子放球数>=0,求方法数
假设n个盒子分别放x1,x2,x3...xn
,则x1+x2+x3+...+xn=k
,令yi=xi+1(1<=i<=n)
,则yi>=1
且y1+y2+...+yn=n+k
,相当于求yi这个方程的解组数,可以看成插板问题,往n+k
个物品中插入n-1
个板,所以答案是C(n+k-1,n-1)=C(n+k-1,k)
/* *输入说明:k个相同的球放入n个不同的盒子 *输入每行有两个正整数n和k */ int com(int n, int m) { m = min(m, n - m); int res = 1; for (int i = 0, j = 1; i < m; i ++) { res *= n - i; while (j <= m && res % j == 0) { res /= j; j ++; } } return res; } int main() { int n, k; while (~scanf("%d %d", &n, &k)) { printf("%d\n", com(n+k-1, k)); } return 0; }
第二类:
m个相同的球放入n个相同的盒子,每个盒子放球数>=0,求方法数
令dp[i][j]表示i个球放入j个盒子的方法数。
当i>j时,分两种情况:
1、每个盒子至少放一个,为dp[i-j][j]
2、存在某个盒子不放,为dp[i][j-1]
所以dp[i][j] = dp[i-j][j] + dp[i][j-1];
当i<=j时,等价于i个球放入i个盒子
const int maxn = 20; int dp[maxn][maxn];//i个球放入j个盒子方法数 void init() { for (int j = 1; j <= 10; j ++) dp[0][j] = dp[1][j] = dp[j][1] = dp[j][0] = 1; for (int i = 2; i <= 10; i ++) { for (int j = 2; j <= 10; j ++) { if (i >= j) dp[i][j] = dp[i-j][j] + dp[i][j-1]; else dp[i][j] = dp[i][i]; } } } int main() { init(); int T, m, n; scanf("%d", &T); while (T --) { scanf("%d %d", &m, &n); printf("%d\n", dp[m][n]); } return 0; }
Read The Fucking Source Code ☺!