黑白球
题目描述
一个箱子里面有n个黑球m个白球。你每小时都随机从箱子里面抽出两个小球,然后把这两个球都染成黑球,然后再放回去。问需要多少小时才能把所有小球变成黑色小球?输出期望值。
输入格式
多组测试数据。
第一行,一个整数G,表示有G组测试数据。 1 < = G < = 10 1<=G<=10 1<=G<=10
每组测试数据格式如下:
一行,两个整数,n和m。 1 < = n 1 <=n 1<=n, m < = 47 m<=47 m<=47。
输出格式
共G行,每行一个实数。误差不能超过0.00001。
输入样例
5
1 1
2 1
1 2
4 7
1 3
输出样例
1.0
1.5
2.0
13.831068977298521
3.4
解题思路
题目大意:有黑白两种球,求将全部球染成黑球的操作次数期望值。
经过一段时间的思考,我们可以发现本题用动态规划解决是比较方便的,可以用二维的动态规划;因为题目中只有两种颜色的球,所以这里采用较方便的一维。
我们设 f [ i ] f[i] f[i]表示盒子里有 i i i个黑球,还要多少小时才能变成 n + m n+m n+m个黑球。很显然,白球数量就是 n + m − i n+m-i n+m−i个。
根据题意,我们要从最开始的 n n n个黑球 f [ n ] f[n] f[n]推到全部变为黑球 f [ n + m ] f[n+m] f[n+m]。
那么 f [ i ] f[i] f[i]是怎么推来的呢?抽球的概率又怎么计算呢?
首先,我们分类讨论:
对于第 i i i次操作:
- 抽到两个黑球
- 抽到两个白球
- 先抽到黑球,再抽到白球
- 先抽到白球,再抽到黑球
对于以上四种情况,我们有以下四条概率计算式:
- 抽到两个黑球的概率是:
i n + m × i − 1 n + m − 1 \frac{i}{n+m}\times\frac{i-1}{n+m-1} n+mi×n+m−1i−1 - 抽到两个白球的概率是:
n + m − i n + m × n + m − i − 1 n + m − 1 \frac{n+m-i}{n+m}\times\frac{n+m-i-1}{n+m-1} n+mn+m−i×n+m−1n+m−i−1 - 先抽到黑球,再抽到白球的概率是:
i n + m × n + m − i n + m − 1 \frac{i}{n+m}\times\frac{n+m-i}{n+m-1} n+mi×n+m−1n+m−i - 先抽到白球,再抽到黑球的概率是:
n + m − i n + m × i n + m − 1 \frac{n+m-i}{n+m}\times\frac{i}{n+m-1} n+mn+m−i×n+m−1i
那么,对于第 i i i次操作,我们运用倒推的方法就可以将式子推出来了。
f [ i ] = 1 + f [ i ] × i n + m × i − 1 n + m − 1 + f [ i − 2 ] × n + m − i n + m × n + m − i − 1 n + m − 1 + f [ i − 1 ] × i n + m × n + m − i n + m − 1 + f [ i − 1 ] × n + m − i n + m × i n + m − 1 f[i]=1+f[i]\times\frac{i}{n+m}\times\frac{i-1}{n+m-1}+f[i-2]\times\frac{n+m-i}{n+m}\times\frac{n+m-i-1}{n+m-1}+f[i-1]\times\frac{i}{n+m}\times\frac{n+m-i}{n+m-1}+f[i-1]\times\frac{n+m-i}{n+m}\times\frac{i}{n+m-1} f[i]=1+f[i]×n+mi×n+m−1i−1+f[i−2]×n+mn+m−i×n+m−1n+m−i−1+f[i−1]×n+mi×n+m−1n+m−i+f[i−1]×n+mn+m−i×n+m−1i
到了这一步,不知大家发现一个问题没有, f [ i ] f[i] f[i]在运算过程中,乘了一遍它自己,那么怎么解决这个问题呢?
利用数学知识:等式两边加一个相同的数,等式仍成立
我们不妨将 f [ i ] × i n + m × i − 1 n + m − 1 f[i]\times\frac{i}{n+m}\times\frac{i-1}{n+m-1} f[i]×n+mi×n+m−1i−1这一项移到左边去。
f [ i ] − f [ i ] × i n + m × i − 1 n + m − 1 = 1 + f [ i − 2 ] × n + m − i n + m × n + m − i − 1 n + m − 1 + f [ i − 1 ] × i n + m × n + m − i n + m − 1 + f [ i − 1 ] × n + m − i n + m × i n + m − 1 f[i]-f[i]\times\frac{i}{n+m}\times\frac{i-1}{n+m-1}=1+f[i-2]\times\frac{n+m-i}{n+m}\times\frac{n+m-i-1}{n+m-1}+f[i-1]\times\frac{i}{n+m}\times\frac{n+m-i}{n+m-1}+f[i-1]\times\frac{n+m-i}{n+m}\times\frac{i}{n+m-1} f[i]−f[i]×n+mi×n+m−1i−1=1+f[i−2]×n+mn+m−i×n+m−1n+m−i−1+f[i−1]×n+mi×n+m−1n+m−i+f[i−1]×n+mn+m−i×n+m−1i
( 1 − i n + m × i − 1 n + m − 1 ) × f [ i ] = 1 + f [ i − 2 ] × n + m − i n + m × n + m − i − 1 n + m − 1 + f [ i − 1 ] × i n + m × n + m − ( i − 1 ) n + m − 1 + f [ i − 1 ] × n + m − i n + m × i n + m − 1 (1-\frac{i}{n+m}\times\frac{i-1}{n+m-1})\times f[i]=1+f[i-2]\times\frac{n+m-i}{n+m}\times\frac{n+m-i-1}{n+m-1}+f[i-1]\times\frac{i}{n+m}\times\frac{n+m-(i-1)}{n+m-1}+f[i-1]\times\frac{n+m-i}{n+m}\times\frac{i}{n+m-1} (1−n+mi×n+m−1i−1)×f[i]=1+f[i−2]×n+mn+m−i×n+m−1n+m−i−1+f[i−1]×n+mi×n+m−1n+m−(i−1)+f[i−1]×n+mn+m−i×n+m−1i
至此,再将 ( 1 − i n + m × i − 1 n + m − 1 ) (1-\frac{i}{n+m}\times\frac{i-1}{n+m-1}) (1−n+mi×n+m−1i−1)移回右边。
f [ i ] = 1 + f [ i − 2 ] × n + m − i n + m × n + m − i − 1 n + m − 1 + f [ i − 1 ] × i n + m × n + m − i n + m − 1 + f [ i − 1 ] × n + m − i n + m × i n + m − 1 ( 1 − i n + m × i − 1 n + m − 1 ) f[i]=\frac{1+f[i-2]\times\frac{n+m-i}{n+m}\times\frac{n+m-i-1}{n+m-1}+f[i-1]\times\frac{i}{n+m}\times\frac{n+m-i}{n+m-1}+f[i-1]\times\frac{n+m-i}{n+m}\times\frac{i}{n+m-1}}{(1-\frac{i}{n+m}\times\frac{i-1}{n+m-1})} f[i]=(1−n+mi×n+m−1i−1)1+f[i−2]×n+mn+m−i×n+m−1n+m−i−1+f[i−1]×n+mi×n+m−1n+m−i+f[i−1]×n+mn+m−i×n+m−1i
这就是最终的动态规划式子了
代码:
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,G;
double f[255],p1,p2,p3;
int main()
{
freopen("2829.in","r",stdin);
freopen("2829.out","w",stdout);
cin>>G;
for(int gr=1;gr<=G;gr++)
{
cin>>n>>m;
f[n+m+1]=f[n+m]=0.0;
for(int i=n+m-1;i>=n;i--)//倒推
{
//f[i]:当前有i个黑球,还要多少个小时才能变成n+m个黑球
//操作一次得到三种情况,转移到相应的子问题
p1=(double(i)/double(n+m))*(double(i-1)/double(n+m-1));//两个黑球
p2=(double(n+m-i)/double(n+m))*(double(n+m-1-i)/double(n+m-1));//两个白球
p3=(double(i)/double(n+m))*(double(n+m-i)/double(n+m-1));//先摸到黑球后摸到白球
p3+=(double(n+m-i)/double(n+m))*(double(i)/double(n+m-1));//先摸到白球后摸到黑球
f[i]=(p2*f[i+2]+p3*f[i+1]+1.00)/(1.00-p1);
}
printf("%.6lf\n",f[n]);
}
return 0;
}