首個概率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 ;
}