1. 程式人生 > >解題報告 之 ZOJ 3329 One Person Game

解題報告 之 ZOJ 3329 One Person Game

解題報告 之 ZOJ 3329 One Person Game



Description

There is a very simple and interesting one-person game. You have 3 dice, namely Die1Die2 and Die3Die1 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 K1K2K3 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 nK1K2K3abc (0 <= n <= 500, 1 < K1K2K3 <= 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

Source

The 7th Zhejiang Provincial Collegiate Programming Contest
題目大意:有三個骰子,每個骰子分別有K1,K2,K3個面,每個骰子分別印著1~Ki 。每個骰子投中每個面概率相等。有一個計數器,一開始清零,當第一二三個骰子分別投中a,b,c時,則計數器清零,否則就加上三個骰子投出的數字和,一旦計數器大於n就停止。問要使得計數器的數大於n需要的步數的期望是多少?
分析:概率dp的題,用dp[i]表示使計數器達顯示n所需要的步數期望。所以很容易得到狀態轉移方程:

p[j]表示投出j的概率,p[0]表示清零概率

但是很不幸的是,遞推公式中包含dp[0],而dp[0]正是我們要求的。不過好在每次遞推dp[0]都是線性變化,所以我們可以考慮將dp[0]視為未知數推導到dp[0]=k*dp[0]+b,解方程即可。

於是乎我們令 dp[i]=A[i]*dp[0]+B[i] 。(因為dp[i]中要麼是關於dp[0]的一次項,要麼是已知常數)。 所以我們可以將上面的狀態轉移方程表示成另一種形式:
於是乎,我們可以得到A[i]和B[i]的狀態轉移方程:
在根據之前的定義:dp[0]=A[0]*dp[0] + B[0]   -->  dp[0]=B[0]/(1.0-A[0])
上程式碼:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;

const int MAXN = 500 + 50;
double A[MAXN], B[MAXN];
double p[50];

int main()
{
	int T;
	cin >> 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 );
		memset( A, 0, sizeof A );
		memset( B, 0, sizeof B );
		memset( p, 0, sizeof p );

		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;

		for(int i = n; i >= 0; i--)
		{
			for(int j = 1; j <= k1 + k2 + k3; j++)
			{
				A[i] += A[i + j]*p[j];
				B[i] += B[i + j]*p[j];
			}
			A[i] += p0;
			B[i] += 1.0;
		}
		printf( "%.16lf\n", B[0] / (1.0 - A[0]) );
	}

	return 0;
}