首个概率DP类题目。题意: 一个软件有S个子系统,会产生n中bug
某人一天发现一个bug,这个bug属于一个子系统并且属于一个分类。每个bug属于某个子系统的概率是1/s,属于某个分类的概率为1/n,求发现n中bug,每个子系统都发现bug的天数的期望。
全期望的公式:E(Y) = E(E(Y|x)) = sgm(P(X=xi)E(Y|X = xi)) ;粘贴公式不方便= =
设dp[i][j] 表示已经找到i种bug,j个子系统的bug,达到目标状态的天数的期望,由于我们可以很容易确定最后的状态,所以逆推。dp[n][s] = 0 ; 答案就是dp[0][0] ;
dp[i][j] 可以转化为如下状态:
(1)如果发现的一个bug为已有的i个分类和j个子系统,概率为(i/n) * (j/s);
(2)如果发现的一个bug为已有的分类,但不属于已有系统,概率为(i/n) * (1 - j/s) ;
(3)如果发现的一个bug不是已有的分类,但是已有的系统,概率为(1- i/n) * (j/s) ;
(4)如果发现的一个bug既不是已有的分类,也不是已有的系统中的,概率为(1 - i/n) * (1 - j/s) ;
然后我们就结合全期望公式整理就可以很容易得到转移方程。代码如下:
/*
author : csuchenan
prog : POJ 2096
algorithm : probability DP
csuchenan 2096 Accepted 8068K 172MS C++ 651B
*/
#include <cstdio>
#include <cstring>
const int maxn = 1005 ;
double dp[maxn][maxn] ;
int main(){
int n , s ;
scanf("%d%d" , &n , &s) ;
dp[n][s] = 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]
+ (n - i) * j * dp[i + 1][j]
+ (n - i) * (s - j) * dp[i + 1][j + 1]
+ n * s )/(n * s - i * j) ;
}
}
printf("%.4f\n" , dp[0][0]) ;
return 0 ;
}