ZOJ3582-Back to the Past-概率dp
一共左右两排共2N盏灯,计算每排都亮M盏以上的期望。每天每盏灯有P的概率点亮。
dp[i][j]记录左边i盏右边j盏时的期望,从dp[N][N]往前推。//没学概率论写的好懵逼。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 50+5; 9 int N,M; 10 double P,dp[maxn][maxn],Yes[maxn],No[maxn],C[maxn][maxn]; 11 12 void init() 13 { 14 for(int i=0;i<=maxn;i++) 15 { 16 C[i][0] = C[i][i] = 1.0; 17 for(int j=1;j<i;j++) 18 C[i][j] = C[i-1][j-1]+C[i-1][j]; 19 } 20 } 21 22 int main() 23 { 24 init(); 25 while(scanf("%d%d%lf",&N,&M,&P)) 26 { 27 if(N==0&&M==0) break; 28 //cout << P << endl; 29 memset(dp,0,sizeof dp); 30 Yes[0]=No[0]=1; 31 for(int i=1;i<=N;i++) 32 { 33 Yes[i] = Yes[i-1]*P; 34 No[i] = No[i-1]*(1.0-P); 35 } 36 37 for(int i=N;i>=0;i--) 38 { 39 for(int j=N;j>=0;j--) 40 { 41 if(i>=M&&j>=M) continue; 42 double sum = 0; 43 for(int x=0;x+i<=N;x++) 44 { 45 for(int y=0;y+j<=N;y++) 46 { 47 if(x==0&&y==0) continue; 48 if(N-i>=x&&N-j>=y) 49 sum += dp[x+i][y+j]*C[N-i][x]*Yes[x]*No[N-i-x]*C[N-j][y]*Yes[y]*No[N-j-y]; 50 } 51 } 52 dp[i][j] = (sum+1.0)/(1.0-No[N-i]*No[N-j]); 53 } 54 } 55 56 printf("%.6f\n",dp[0][0]); 57 } 58 }