zoj 3329 概率dp 环

一个游戏,你手上有三个骰子,分别有k1, k2, k3面。每次投出这三个骰子,得到三个面x, y, z。并且你有一个计数器,如果投出a, b, c, 则计数器归零,否则计数器加上三面之和,计数器初始为零。如果计数器的值大于 n 则游戏胜利。求胜利所需投骰子次数的期望。
以计数器的值为状态,dp[i] 表述计数器的值为i的情况下投骰子的期望。得到转移方程

p[k] 表示投出点数总和为k的概率,k=0时表示投出计数器归零的概率。
dp[i] = p[0]* dp[0] + Σ(dp[i+k]*p[k]) + 1;

然后dp方程有环,=_=

用待定系数法推,先设:
dp[i] = a[i]*dp[0] + b[i];

带入原方程得
dp[i] = p[0]* dp[0] + Σ(p[k]* (a[i+k]*dp[0]+b[i+k])) + 1;
dp[i] = (p[0]+Σ(p[k]* a[i+k]))* dp[0] + Σ(p[k]*b[i+k]) + 1;

得出:
a[i] = p[0]+Σ(p[k]*a[i+k]);
b[i] = Σ(p[k]*b[i+k]) + 1;

而:
dp[0] = a[0] * dp[0] + b[0];

于是我们根据a[i] 和 b[i] 可以算出:
dp[0] = b[0] / (1 - a[0]);

/***********************************************
 ** problem ID  : zoj_3329.cpp
 ** create time : Sat Jul 25 15:02:55 2015
 ** auther name : xuelanghu
 ** auther blog : blog.csdn.net/xuelanghu407
 **********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int n;
int k1, k2, k3, _k;
int a, b, c;

double ans;

double p[20];

void init () {
    memset(p, 0, sizeof(p));

    p[0] = 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) continue;
                p[i + j + k] += 1.0 / (k1 * k2 * k3);
            }
        }
    }
}


void solve() {
    double A[520];
    double B[520];
    memset(A, 0, sizeof(A));
    memset(B, 0, sizeof(B));
    for (int i=n; i>=0; i--) {
        A[i] = p[0]; 
        B[i] = 1.0;
        for (int j=3; j<=_k; j++) {
            A[i] += p[j] * A[i+j] * 1.0;
            B[i] += p[j] * B[i+j] * 1.0;
        }
    }
    ans = B[0] * 1.0 / (1.0 - A[0]);
}

int main () {
    int T;
    cin >> T;
    while (T--) {
        cin >> n;
        cin >> k1 >> k2 >> k3; 
        cin >> a >> b >> c;
        _k = k1 + k2 + k3;      
        init ();        
        solve();
        printf ("%.15lf\n", ans);
    }
    return 0;
}

这种成环的dp转移关键在于找到他的待定系数方程。然而并不是都像这题一样那么好推。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值