题意
一个软件有s个子系统,这个软件会产生n种bug。
某人一天发现一个bug,这个bug属于n种bug中的某种bug,发生在某个子系统中。
求找到所有的n种bug,且每个子系统都找到bug,这样所要的天数的期望。
题解
找到某种bug的概率是1/n,属于某个子系统的概率是1/s。
设dp[i][j]是找到了i种bug,存在于j个子系统中,此状态下达到目标天数的期望。
dp[n][s]是最终的状态,然而在状态dp[n][s]为0,所以要找期望的状态是dp[0][0]。
dp[i][j]的状态转移方程有四种
1.dp[i][j] 新发现一个bug属于已经找到i种bug和已经存在的j个子系统中。
2.dp[i+1][j] 新发现的bug属于新的bug,存在于已有的j个子系统中。
3.dp[i][j+1] 新发现的bug属于已有i种,但属于新的子系统中。
4.dp[i+1][j+1] 新发现的bug属于新的,且存在于新的子系统中。
四种情况的概率是
p1 = i*j / (n*s)
p2 = (n-i)*j / (n*s)
p3 = i*(s-j) / (n*s)
p4 = (n-i)*(s-j) / (n*s)
转移方程
dp[i,j] = p1*dp[i,j] + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] + 1;
整理得
dp[i,j] = ( 1 + p2*dp[i+1,j] + p3*dp[i,j+1] + p4*dp[i+1,j+1] )/( 1-p1 )
= ( n*s + (n-i)*j*dp[i+1,j] + i*(s-j)*dp[i,j+1] + (n-i)*(s-j)*dp[i+1,j+1] )/( n*s - i*j )
代码
#include <iostream>
#include <string.h>
#include <string>
#include <stdio.h>
using namespace std;
const int maxn = 1010;
int n, s;
double dp[maxn][maxn];
int main()
{
while(~scanf("%d%d", &n, &s))
{
dp[n][s] = 0.0;
double ns = n*s;
for(int i = n; i >= 0; i--)
{
for(int j = s; j >= 0; j--)
{
if(i == n && j == s) continue;
dp[i][j] = (ns + (n-i)*j*dp[i+1][j] + \
i*(s-j)*dp[i][j+1] + \
(n-i)*(s-j)*dp[i+1][j+1])/(ns - i*j);
}
}
printf("%.4lf\n", dp[0][0]);
}
return 0;
}