【概率DP】zoj 3329

刷着刷着概率DP专题,一脸懵逼的情况下翻到了一个博客,概率DP三部曲,感觉自己对期望这一块真的是很不熟悉啊,今天又来取经一把。


题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3329
题目大意:有三个筛子,他们可以摇出来的点数分别是k1,k2,k3,每次摇完,如果k1 = a,k2 = b,k3 = c则总统计数清零,否则加上摇出来的点数,现在问你摇到n以上的次数的期望是多少。

拿到题目第一时间应该要求出,摇到每次一的点数的概率为多少,然后清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],且,当期望数中出现常数项,要记得化简。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值