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

 

 

你可能感兴趣的:(game)