ZOJ 3329 One Person Game——(概率DP+待定係數求解方程)

傳送門

There is a very simple and interesting one-person game. You have 3 dice, namely Die1, Die2 and Die3. Die1 has K1 faces. Die2 has K2 faces. Die3 has K3 faces. All the dice are fair dice, so the probability of rolling each value, 1 to K1, K2, K3 is exactly 1 / K1, 1 / K2 and 1 / K3. You have a counter, and the game is played as follow:

  1. Set the counter to 0 at first.
  2. Roll the 3 dice simultaneously. If the up-facing number of Die1 is a, the up-facing number of Die2 is b and the up-facing number of Die3 is c, set the counter to 0. Otherwise, add the counter by the total value of the 3 up-facing numbers.
  3. If the counter’s number is still not greater than n, go to step 2. Otherwise the game is ended.

Calculate the expectation of the number of times that you cast dice before the end of the game.

Input

There are multiple test cases. The first line of input is an integer T (0 < T <= 300) indicating the number of test cases. Then T test cases follow. Each test case is a line contains 7 non-negative integers n, K1, K2, K3, a, b, c (0 <= n <= 500, 1 < K1, K2, K3 <= 6, 1 <= a <= K1, 1 <= b <= K2, 1 <= c <= K3).

Output

For each test case, output the answer in a single line. A relative error of 1e-8 will be accepted.

Sample Input

2
0 2 2 2 1 1 1
0 6 6 6 1 1 1

Sample Output

1.142857142857143
1.004651162790698

題目大意:

有三個骰子,分別有 k1,k2,k3(1<k1,k2,k36) 個面,現在有如下 3 個操作:
(1) 首先將計數器設置爲 0
(2) 如果骰子 1 朝上的面是 a , 骰子 2 朝上的面是 b , 骰子 3 朝上的面是 c 的時候,計數器設置爲 0 ,否則計數器加上三個面朝上的面的和
(3) 如果計數器的值 n ,跳到第 2 步,否則遊戲結束。
現在計算遊戲結束前擲骰子的次數期望。

解題思路:

dp[x] 表示當前計數器爲 x 到遊戲結束時候的擲骰子的次數期望
p[x] 表示三個骰子朝上的面的和爲 x 的概率。那麼有如下方程成立:

dp[x]=k=3k1+k2+k3p[k]dp[x+k]+p[0]dp[0]+1(1)

然後觀察這個式子發現,這個石子都跟 dp[0] 有關,那麼我們將 dp[0] 看作未知數,那麼 dp[x] 都是跟 dp[0] 有關,我們可以根據待定係數法求一下 dp[0] ,設:
dp[x]=A[x]dp[0]+B[x](2)

將式子 (1) 用式子 (2) 表達一下:
dp[x]=k=3k1+k2+k3p[k](A[x+k]dp[0]+B[x+k])+p[0]dp[0]+1=(k=3k1+k2+k3p[k]A[x+k]+p[0])dp[0]+k=3k1+k2+k3p[k]B[x+k]+1

將這個式子與第 (2) 個式子進行比較然後係數與係數相同:
{A[x]=k1+k2+k3k=3p[k]A[x+k]+p[0]B[x]=k1+k2+k3k=3p[k]B[x+k]+1

然後通過這兩個遞推式求出 A[0],B[0] ,然後 dp[0]=A[0]dp[0]+B[0]
解得 dp[0]=B[0]1A[0]

代碼:

#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN = 5e2+20;
const double PI = acos(-1);
const double eps = 1e-8;
const LL MOD = 1e9+7;
double p[20], A[MAXN], B[MAXN];
void Init(){
    memset(p, 0, sizeof(p));
    memset(A, 0, sizeof(A));
    memset(B, 0, sizeof(B));
}
int main(){
    //freopen("C:/Users/yaonie/Desktop/in.txt", "r", stdin);
    //freopen("C:/Users/yaonie/Desktop/out.txt", "w", stdout);
    int T;
    while(~scanf("%d", &T)){
        while(T--){
            int n, k1, k2, k3, a, b, c; scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
            Init();
            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] += p[0];
                    }
                }
            }
            for(int i=n; i>=0; i--){
                A[i] = p[0], B[i] = 1;
                for(int k=3; k<=k1+k2+k3; k++){
                    A[i] += (p[k]*A[i+k]);
                    B[i] += (p[k]*B[i+k]);
                }
            }
            printf("%.15f\n",B[0]/(1-A[0]));
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章