ZOJ 3329 One Person Game (经典概率dp+有环方程求解)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3329

题意:
现在有三个骰子,分别有k1,k2和k3面,面上的点就是1~ki。每次扔骰子,如果这三个骰子的值分别对应为a,b,c,那么将值初始化为0,否则就将三个骰子的点值和相加。求大于等于n的扔骰子次数期望。

思路:

这道题目主要在于推公式,看着别人的题解想了好久。

先设$E(i)$为此时和为i时还需要的期望,易得(1):$E(i)=sum (E(i+k)P(k))+E(0)P(0)+1$(这里$P(k)$为点值和为k的概率,$P(0)$就是对应a,b,c的概率)。

现在我们要求解的是$E(0)$,而且发现每个式子中都会包含$E(0)$。

当遇到这样的情况时我们可以先假设一下,假设(2):$E(i)=A(i)E(0)+B(i)$,那么(3):$E(i+k)=A(i+k)E(0)+B(i+k)$。

将(3)式带入(1)式,得(4):$E(i)=(sum (A(i+k)P(k))+P(0))*E(0)+sum (B(i+k)P(k))+1$。

将(2)式和(4)式作比较,可得:

(5):$A(i)=sum (A(i+k)P(k))+P(0)$

(6):$B(i)=sum (B(i+k)P(k))+1$

而由(2)式我们又可以推出$E(0)=frac{B(0)}{1-A(0)}$。

所以现在要的就是A(0)和B(0)的值,这个很简单,由(5)、(6)递推得到即可。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<vector>
 6 #include<stack>
 7 #include<queue>
 8 #include<cmath>
 9 #include<map>
10 #include<set>
11 using namespace std;
12 typedef long long ll;
13 const int INF = 0x3f3f3f3f;
14 const int maxn=500+5;
15 
16 int n,k1,k2,k3,a,b,c;
17 double p0;
18 double A[maxn],B[maxn],p[maxn];
19 
20 int main()
21 {
22     //freopen("in.txt","r",stdin);
23     int T;
24     scanf("%d",&T);
25     while(T--)
26     {
27         cin>>n>>k1>>k2>>k3>>a>>b>>c;
28         memset(p,0,sizeof(p));
29         p0=1.0/k1/k2/k3;
30         for(int i=1;i<=k1;i++)
31         for(int j=1;j<=k2;j++)
32         for(int t=1;t<=k3;t++)
33         {
34             if(i==a && j==b && t==c)  continue;
35             p[i+j+t]+=p0;
36         }
37         for(int i=n;i>=0;i--)
38         {
39             A[i]=p0,B[i]=1;
40             for(int t=3;t<=k1+k2+k3;t++)
41             {
42                 if(i+t>n)  continue;
43                 A[i]+=A[i+t]*p[t];
44                 B[i]+=B[i+t]*p[t];
45             }
46         }
47         printf("%.16f
",B[0]/(1-A[0]));
48     }
49     return 0;
50 }
原文地址:https://www.cnblogs.com/zyb993963526/p/7449467.html