【概率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],且,當期望數中出現常數項,要記得化簡。