ZOJ 3329 One Person Game 概率dp、求期望

概率求期望入门推荐文章:

http://kicd.blog.163.com/blog/static/126961911200910168335852/

题意:(有环、倒推)

投掷3枚骰子,如果dice1 = a,dice2 = b,dice3 = c。那么你的点数置为0,否则加上这三枚点数之和。

问你点数最终超过n,所需要投掷次数的期望。


思路:

正如我们所见,这个期望是有环的,就是可以可以回到0,因此我们需要进行式子替换。

dp[i]:从i出发,到游戏结束所需要投掷骰子次数的期望。

引用一下别人的blog:(http://blog.csdn.net/xingyeyongheng/article/details/25639827)

(1):dp[i]=SUM(p[k]*dp[i+k])+p[0]*dp[0]+1;//p[k]表示增加分数为k的概率,p[0]表示分数变为0的概率 
假定 
(2):dp[i]=A[i]*dp[0]+B[i]; 
则 
(3):dp[i+k]=A[i+k]*dp[0]+B[i+k]; 
将(3)代入(1)得: 
(4):dp[i]=(SUM(p[k]*A[i+k])+p[0])*dp[0]+SUM(p[k]*B[i+k])+1; 
将4与2做比较得: 
A[i]=(SUM(p[k]*A[i+k])+p[0]); 
B[i]=SUM(p[k]*B[i+k])+1; 
当i+k>n时A[i+k]=B[i+k]=0可知 
所以dp[0]=B[0]/(1-A[0])可求出 

code:

#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <iomanip>
#include <algorithm>
#include <iostream>
using namespace std;

typedef long long LL;
const int MAXN = 550;

double a[MAXN], b[MAXN], dp[MAXN];
double p[30];
int main()
{
    ios::sync_with_stdio(false);
    int T;
    int n, k1, k2, k3, A, B, C;
    while(cin>>T)
    {
        while(T--)
        {
            cin>>n>>k1>>k2>>k3>>A>>B>>C;

            double t = 1.0/(k1*k2*k3);
            //get the Matrix p;
            memset(p, 0, sizeof(p));
            p[0] = t;
            for(int i = 1;i <= k1; i++)
                for(int j = 1;j <= k2; j++)
                    for(int z = 1;z <= k3; z++)
                            p[i+j+z] += t;

            //get the Matrix a, b;
            p[A+B+C] -= p[0];
            int tot = k1+k2+k3;
            memset(a, 0, sizeof(a));
            memset(b, 0, sizeof(b));
            for(int tn = n; tn >= 0; tn--)
            {
                a[tn] = p[0];
                b[tn] = 1;
                for(int i = 3;i <= tot; i++)
                {
                    if(p[i] != 0)
                    {
                        a[tn] += a[tn+i] * p[i];
                        b[tn] += b[tn+i] * p[i];
                    }
                }
            }
            
            //get the dp[0];
            //cout<<"a[0] = "<<a[0]<<endl;
            //cout<<"b[0] = "<<b[0]<<endl;
            double res = b[0]/(1-a[0]);
            cout<<fixed<<setprecision(8)<<res<<endl;
        }
    }
    return 0;
}

            


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值