ZOJ 3329 One Person Game 【概率DP,求期望】

题意:有三个骰子,分别有k1,k2,k3个面。

每次掷骰子,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和。

当分数大于n时结束。求游戏的期望步数。初始分数为0

 

设dp[i]表示达到i分时到达目标状态(即i = n)的期望,pk为投掷k分的概率,

p0为回到0的概率则dp[i] = ∑(pk * dp[i + k]) + dp[0] * p0 + 1 ;

都和dp[0]有关系,而且dp[0]就是我们所求,为常数设

  dp[i] = A[i] * dp[0] + B[i];

即为dp[i + k] = A[i + k] * dp[0] + B[i + k];

将其代入原式:dp[i] = ∑(pk * A[i + k] * dp[0] + pk * B[i + k]) + dp[0] * p0 + 1

          = (∑(pk * A[i + k]) + p0) * dp[0] + ∑(pk * B[i + k]) + 1;

所以可得:A[i] = ∑(pk * A[i + k]) + p0
        B[i] = ∑(pk * B[i + k]) + 1

先递推求得A[0]和B[0]。那么 dp[0] = B[0] / (1 - A[0]);

 

Source Code:

//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <vector>
#include <algorithm>
#define Max(a,b) (((a) > (b)) ? (a) : (b))
#define Min(a,b) (((a) < (b)) ? (a) : (b))
#define Abs(x) (((x) > 0) ? (x) : (-(x)))
#define MOD 1000000007
#define pi acos(-1.0)

using namespace std;

typedef long long           ll      ;
typedef unsigned long long  ull     ;
typedef unsigned int        uint    ;
typedef unsigned char       uchar   ;

template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;}
template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;}

const double eps = 1e-7      ;
const int N = 210            ;
const int M = 1100011*2      ;
const ll P = 10000000097ll   ;
const int MAXN = 10900000    ;

int n, k1, k2, k3, ka, kb, kc;
double a[600], b[600], p[100];

int main(){
    std::ios::sync_with_stdio(false);
    int i, j, t, k, u, v, numCase = 0;
    cin >> t;
    while(t--){
        cin >> n >> k1 >> k2 >> k3 >> ka >> kb >> kc;
        memset(p, 0, sizeof(p));
        for(i = 1; i <= k1; ++i){
            for(j = 1; j <= k2; ++j){
                for(k = 1; k <= k3; ++k){
                    if(i == ka && j == kb && k == kc){
                        p[0] += 1.0 / (k1 * k2 * k3);
                        continue;
                    }
                    p[i + j + k] += 1.0 / (k1 * k2 * k3);
                }
            }
        }
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        for(i = n; i >= 0; --i){
            a[i] = p[0];
            b[i] = 1.0;
            for(k = 1; k <= k1 + k2 + k3; ++k){
                a[i] += p[k] * a[i + k];
                b[i] += p[k] * b[i + k];
            }
        }
        printf("%.16f\n",b[0] / (1.0 - a[0]));
    }

    return 0;
}

 

posted @ 2015-03-15 16:10  Jeremy Wu  阅读(159)  评论(0编辑  收藏  举报