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:
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
今天刚刚讲了这题,经过连教的指导,明白了这题的精髓,数学期望的题一般有dp解,但dp一般只能够解有向无环图(DAG),如果有环必然状态循环,这题是有环图,但是有巧妙的处理后可以得出结果。
题意是给你三个骰子,分别有k1,k2,k3个面,设初始分数为0,当分数>=n结束,但是当你掷三个骰子分别为a,b,c的时候分数清0;这题的状态很好转移,E(i)=sum(Pk*E(i+k))+P0*E(0)+1;(i表示当前分数,而pk表示三骰子总和为k的概率,E存储的是分数i距离n还差的期望(需要投掷的平均次数),加一表示加入当前这次投掷),如果不懂这里的话请参考我的另一题poj2096,这里懂的话,就进入关键步骤,由方程你会发现,每个E(i)都包含E(0),而E(0)又是我们要求的结果,显然是个定值,我们是否可以像数学中那样分离参数呢,显然是可以的可以写这样一个方程设E(i)=a(i)*E(0)+b(i);显然将这个式子带入E(i)=sum(Pk*E(i+k))+P0*E(0)+1,可以得到一个关于E[i]和E[0],a[i],b[i]的特征方程,得到E[i]=(sum(a[i+k])+p0)*E[0]+sum(b[i+k])+1;显然a[i]=sum(a[i+k])+p0)*E[0],b[i]=sum(b[i+k])+1,而由E(i)=a(i)*E(0)+b(i)可以得出E[0]=a(0)*E(0)+b(0);得到E[0]=b[0]/(1-a[0]);,我们只需要,得到a[0],b[0],即可,而a[i],b[i]的状态转移方程也有了,出状态也容易求E[n]=0,所以a[n]=0,b[n]=0;
下面是我的代码
#include<cstdio> #include<cstring> double p[19],tem; int s,k1,k2,k3,a,b,c; void init() { tem=1.0/(k1*k2*k3); s=k1+k2+k3; memset(p,0,sizeof(p)); 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]+=tem; } } void dp(int n) { double a[501]={0},b[501]={0}; for(int i=n;i>=0;i--) { for(int k=3;k<=s&&(i+k)<=n;k++) { a[i]+=a[i+k]*p[k]; b[i]+=b[i+k]*p[k]; } a[i]+=tem; b[i]+=1; } printf("%.15lf\n",b[0]/(1-a[0])); } int main() { int m,n; scanf("%d",&m); while(m--) { scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c); init(); dp(n); } return 0; }