1. 程式人生 > >概率DP——求期望

概率DP——求期望

ble double 四種 bug 導出 -i 鏈接 emc str

  一般求期望類題目都是倒著來做的,dp[i]表示i狀態下要達到要求狀態的期望值,於是dp[0]就是我們要找的答案,我們可以通過此來推狀態轉移方程,可以得到dp[i]=Σ(dp[k>i]*p[k])+ 1,由於由k狀態轉移到i狀態會多一步操作,這多的一步乘以每種概率再求和剛好等於1,所以轉移公式後面有一個加一。

POJ 2096
題目鏈接:http://poj.org/problem?id=2096

一個軟件有s個子系統,會產生n種bug
某人一天發現一個bug,這個bug屬於一個子系統,屬於一個分類
每個bug屬於某個子系統的概率是1/s,屬於某種分類的概率是1/n
問發現n種bug,每個子系統都發現bug的天數的期望。

dp[i][j]表示已經找到了i種bug,j個系統的bug的情況下要達到要求的天數的期望,
dp[i>=n][j>=s]=0,答案就是dp[0][0],於是dp[i][j]可以轉化為以下四種情況:
1、發現一個bug存在於已有系統和bug,dp[i][j],概率(i*j)/(n*s);
2、發現一個bug存在於已有bug,未知系統,dp[i][j+1],概率i*(s-j)/(n*s);
3、發現一個bug存在於已有系統,未知bug,dp[i+1][j],概率(n-i)*j/(n*s);
4、發現一個bug全都是未知,dp[i+1][j+1],概率(n-i)*(s-j)/(n*s);
於是可以得到狀態轉移方程(經化簡)dp[i][j]=(dp[i+1][j+1]*(n-i)*(s-j)+dp[i+1][j]*(n-i)*j+dp[i][j+1]*i*(s-j)+n*s)/(n*s-i*j);

 1 //#include<bits/stdc++.h>
 2 #include<stdio.h>
 3 #include<string.h>
 4 using namespace std;
 5 double dp[1010][1010];
 6 int main()
 7 {
 8     int n,s;
 9     while(~scanf("%d%d",&n,&s))
10     {
11         memset(dp,0,sizeof(dp));
12         for(int i=n;i>=0;i--)
13             for
(int j=s;j>=0;j--) 14 if(i!=n||j!=s) 15 dp[i][j]=(dp[i+1][j+1]*(n-i)*(s-j)+dp[i+1][j]*(n-i)*j+dp[i][j+1]*i*(s-j)+n*s)/(n*s-i*j); 16 printf("%.4f\n",dp[0][0]); 17 } 18 return 0; 19 }

ZOJ 3329
題目鏈接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3329

有三個骰子,分別有k1,k2,k3個面。
每次擲骰子,如果三個面分別為a,b,c則分數置0,否則加上三個骰子的分數之和。
當分數大於n時結束。求遊戲的期望步數。初始分數為0

dp[i]表示在i分數的情況下要達到要求的期望,於是可以很簡單推導出狀態轉移方程dp[i]=Σ(p[k]*dp[i+k])+dp[0]*p[0]+1;
所有的dp[i]都和dp[0]有關,而且dp[0]就是我們要求的答案,於是可以變形為dp[i]=a[i]*dp[0]+b[i],
所以dp[i]=Σ(p[k]*(a[i+k]*dp[0]+b[i+k]))+dp[0]*p[0]+1
=(Σp[k]*a[i+k]+p[0])*dp[0]+Σp[k]*b[i+k]+1;
最後可以得到dp[0]=a[0]*dp[0]+b[0],dp[0]=b[0]/(1-a[0]);

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 double p[20];
 4 int main()
 5 {
 6     int t;
 7     scanf("%d",&t);
 8     while(t--)
 9     {
10         memset(p,0,sizeof(p));
11         int n,k1,k2,k3,A,B,C;
12         scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&A,&B,&C);
13         p[0]=1.0/(double)(k1*k2*k3);
14         for(int i=1;i<=k1;i++)
15             for(int j=1;j<=k2;j++)
16                 for(int k=1;k<=k3;k++)
17                     if(i!=A||j!=B||k!=C)
18                         p[i+j+k]+=p[0];
19         double a[510]={0},b[510]={0};
20         for(int i=n;i>=0;i--)
21         {
22             for(int j=3;j<=k1+k2+k3;j++)
23             {
24                 a[i]+=a[i+j]*p[j];
25                 b[i]+=b[i+j]*p[j];
26             }
27             a[i]+=p[0];
28             b[i]+=1.0;
29         }
30         printf("%.15lf\n",b[0]/(1-a[0]));
31     }
32     return 0;
33 }

概率DP——求期望