题目: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 ", ans); 42 } 43 return 0; 44 }