1. 程式人生 > >【概率DP】zoj 3329

【概率DP】zoj 3329

刷著刷著概率DP專題,一臉懵逼的情況下翻到了一個部落格,概率DP三部曲,感覺自己對期望這一塊真的是很不熟悉啊,今天又來取經一把。

拿到題目第一時間應該要求出,搖到每次一的點數的概率為多少,然後清0的那一次得要單獨除去

double p0 = 1.0 / (k1 * k2 * k3);
for(int i = 1;i <= k1;i++){
    for(int j = 1;j <= k2;j++){
        for(int k = 1;k <= k3;k++){
            if(i != a || j != b || k != c){
                p[i + j + k] += p0;
            }
        }
    }
}

第一件事情做完之後,我們就來推公式把
很容易能推出來,i表示當前點數,明顯有E[i > n] = 0,則E[0]為所需要的答案
E[i] = ΣP[j] * E[i + j] + P[0] * E[0] + 1 —①
這裡注意為什麼要加1,因為這次是上次搖完的下一次增加了一次次數,所以期望肯定+1
注意到每一個E[i]都存在一個E[0],那我們不妨設一個方程式:
E[i] = a[i] * E[0] + b[i] —②
將②式帶入①式中可得
E[i] = ΣP[j] * (a[i + j] * E[0] + b[i + j]) + P[0] * E[0] + 1
化簡得
E[i] = (ΣP[j] * a[i + j] + P[0]) * E[0] + ΣP[j] * b[i + j] + 1
那麼可以得知
a[i] = ΣP[j] * a[i + j] + P[0]
b[i] = ΣP[j] * b[i + j] + 1

由E[i > n] = 0可知
a[i > n] = 0,b[i > n] = 0
從n開始往前推,可以把a[n -> 0] 和b[n -> 0]推出

當i == 0時,有
E[0] = a[0] * E[0] + b[0]
E[0] = b[0] / (1 - a[0])
E[0]即為答案

下面附上程式碼

/*
@resouces: zoj 3329
@date: 2017-3-13
@author: QuanQqqqq
@algorithm: 概率dp 
*/
#include <stdio.h>
#include <string.h>
#define MAXN 20 #define MAXT 525 double E[MAXN],p[MAXN]; double ao[MAXT],bo[MAXT]; int main(){ int T; scanf("%d",&T); while(T--){ int k1,k2,k3,a,b,c,n; scanf("%d %d %d %d %d %d %d",&n,&k1,&k2,&k3,&a,&b,&c); memset(p,0,sizeof(p)); memset(E,0,sizeof(E)); double p0 = 1.0 / (k1 * k2 * k3); for(int i = 1;i <= k1;i++){ for(int j = 1;j <= k2;j++){ for(int k = 1;k <= k3;k++){ if(i != a || j != b || k != c){ p[i + j + k] += p0; } } } } memset(ao,0,sizeof(ao)); memset(bo,0,sizeof(bo)); int ks = k1 + k2 + k3; for(int i = n;i >= 0;i--){ for(int j = 3;j <= ks;j++){ ao[i] += p[j] * ao[j + i]; bo[i] += p[j] * bo[j + i]; } ao[i] += p0; bo[i] += 1; } printf("%.15lf\n",bo[0] / (1 - ao[0])); } }

總感覺這一套做下來,對數學期望又有了一定的新瞭解通常所要求的>n的期望都為0,所需要求的期望都為E[0],且,當期望數中出現常數項,要記得化簡。