题面
![](https://i-blog.csdnimg.cn/blog_migrate/c4ae65cf3591704c9f1cc563ab579c10.png)
解题:
咦?这不排列组合嘛!于是就开始用高中的知识快乐地演算……越算越不对……诶,最终与自己和解:
以我微薄的数学知识水平,无法用排列组合里的A几取几和C几取几来解决……
动态规划dp
先创建二维数组dp[i][j]来储存,有i个球、j个盒子时的放法数。
首先,不难算出,4个球3个盒子的可能数:36种,即dp[4][3]=36……
于是,我们就以4球3盒为例,推理答案得到的过程:
4个球,可以视为3个球和1个外来球,用绿竖线分割,
![](https://i-blog.csdnimg.cn/blog_migrate/7826290ee815431d25784b8f906cba50.png)
我们可以先把左边的3个球放入盒子,于是我们得到了剩余空盒子的可能数:
剩余1个空盒子或者没有剩余的空盒子(不可能剩余2个以上,否则无法满足每个盒子都有球)
![](https://i-blog.csdnimg.cn/blog_migrate/8eef65ae272f6fc748ceffd88a08ecbe.png)
对于剩下1个空盒子的情况:
看,我们在将左边这3个球放入2个盒子的情况数,难道不就是dp[3][2]么?
而对于这1个外来球,它必须放入唯一的空盒子,
盒子的数量有3个,每一个盒子都有可能成为那个空盒子,
因此,我们还需要对dp[3][2]×3,即为剩下1空盒子的总放法数;
![](https://i-blog.csdnimg.cn/blog_migrate/8544b1995ab7615df4e68303a3726ed9.png)
对于无空盒子的情况:
同样,我们在将左边这3个球放入3个盒子的情况数,难道不就是dp[3][3]么?
而对于这1个外来球,它可以任选一个盒子放,即C3取1
对dp[3][3]×3,即为无空盒子的总放法数;
最后,我们把这两种情况加起来:
dp[4][3]=dp[3][3]×3+dp[3][2]×3=6×3+6×3=36!
和我们最初计算的dp[4][3]答案相同!
故,状态转移方程:dp[i][j]=j×(dp[i-1][j-1]+dp[i-1][j])
注:i为球数,j为盒子个数
AC代码奉上
#include<iostream>
#include<cmath>
using namespace std;
int n, r, ans = 1; //n个球,r个盒子
int dp[100][100] = { 0 }; //球数、盒子数
int main()
{
cin >> n >> r;
for (int i = 1; i <= n; i++)
dp[i][1] = 1; //初始化边界
for (int i = 2; i <= n; i++) //球
for (int j = 2; j <= i; j++)//盒
dp[i][j] = j * (dp[i - 1][j - 1] + dp[i - 1][j]);
cout << dp[n][r] << endl;
return 0;
}