题目链接:哆啦A梦传送门
题意:一个软件有s个系统,n个bug,每个系统有无数个bug,每天可以找出一个bug。
问:每个系统至少找出一个bug,并且所有种类的bug都找出来的期望天数?
题解:
期望dp。
我们设dp[i][j]表示已在j个系统中找出了i个bug,并且距离目标状态的期望天数。
很显然dp[i][j]可以有下面四个状态转移而来。
1,由dp[i][j]转移而来,意味着此次找到的bug既不是新的bug种类,也不是在新系统找出来的,那么此时由该状态转移而来的概率为: p1=i*j/n*s。
2,由dp[i+1][j]转移而来,意味着此次找到的bug是新的bug种类,但不是在新系统找出来的,那么此时由该状态转移而来的概率
为:p2=(1-i/n)*(j/s)=(j*(n-i))/n*s
3,由dp[i][j+1]转移而来,意味着此次找的bug不是新的种类,但是在新系统找出来的,那么此时由该状态转移而来的概率
为:p3=(1-j/s)*(i/n)=(i*(s-j))/n*s。
4,由dp[i+1][j+1]转移而来,意味着此次找到bug既是新的种类,也是在新系统找出来的,那么此时由该状态转移而来的概率
为:p4=(1-i/n)*(1-j/s)=(s-j)*(n-i)/n*s。
期望可以分解成多个子期望的加权和,权为子期望发生的概率,即 E(aA+bB+...) = aE(A) + bE(B) +...
所以:
dp[i][j]=dp[i][j]*p1+dp[i+1][j]*p2+dp[i][j+1]*p3+dp[i+1][j+1]*p4+1。(后面+1,因为可以从四个其中一个转移而来,要花费一天的时间)
最后整理得: dp[i][j]=(i*(s-j)*dp[i][j+1]+(n-i)*j*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1]+n*s)/(n*s-i*j)。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1010;
double dp[N][N];
int main()
{
int n,s;
scanf("%d%d",&n,&s);
dp[n][s]=0.0;
for(int i=n;i>=0;i--)
{
for(int j=s;j>=0;j--)
{
if(i==n&&j==s) continue;
dp[i][j]=(i*(s-j)*dp[i][j+1]+j*(n-i)*dp[i+1][j]+(n-i)*(s-j)*dp[i+1][j+1]+n*s)/(double)(n*s-i*j);
}
}
printf("%.4f\n",dp[0][0]);
return 0;
}