zoj 3329 One Person Game <概率DP>

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

题意:有三个均匀的骰子,分别有k1,k2,k3个面,初始分数是0,当掷三个骰子的点数分别为a,b,c的时候,分数清零,

         否则分数加上三个骰子的点数和, 当分数>n的时候结束。求需要掷骰子的次数的期望~

思路: 设 dp[i] 为分数为i时还需要的期望值, 那么dp[i]= ∑(dp[i+k]*pk ) + dp[0]*p0 +1; 

    设dp[i]= A[i] *dp[0] + B[i];  代入上式得 : dp[i] = ∑( A[i+k]*dp[0] +B[i+k] ) + dp[0]*p0 + 1 ;

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

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

    初始化 : 当 i >= N 时, dp[i]=A[i]*dp[0] + B[i]=0;

    然后可以递推求 A[0], B[0] , dp[0]= A[0]*dp[0]+B[0] = B[0]./ (1-A[0] ) ;

 

   

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int T, N, k1, k2, k3, a, b, c;
 6 double p0, p[20], A[550], B[550];
 7 
 8 void gao(  )
 9 {
10     for(int i=1; i<=k1; ++ i ){
11         for( int j=1; j<=k2; ++ j ){
12             for( int k=1; k<=k3; ++ k ){
13                 if ( i != a || j != b || k != c ) //
14                 p[i+j+k]+=p0;
15             }
16         }
17     }
18 
19 }
20 int main( )
21 {
22     scanf("%d", &T);
23     while(T--){
24         scanf("%d%d%d%d%d%d%d", &N, &k1, &k2, &k3, &a, &b, &c);
25         p0=1.0/(k1*k2*k3);
26 
27         int t=k1+k2+k3;
28         memset(A, 0, sizeof A);
29         memset(B, 0, sizeof B);
30         memset(p, 0, sizeof p);
31         gao( );
32         for( int i=N; i>=0; --i ){
33             for( int k=3; k<=t; ++ k) {
34                 A[i]+=A[i+k]*p[k];
35                 B[i]+=B[i+k]*p[k];
36             }
37             A[i]+=p0; //
38             B[i]+=1;
39         }
40         double ans=B[0]/(1-A[0]);
41         printf("%.15lf\n", ans);
42     }
43     return 0;
44 }
View Code

 

 

posted @ 2013-08-07 20:17  淡墨æ末央  阅读(123)  评论(0编辑  收藏  举报