ZOJ--3329(概率DP,推导)

2015-01-03 12:34:02

思路:这题是概率DP,公式不好推.....一定要细心。(晚上推到凌晨,早上起来再推终于过了.....I am so ruo!QAQ)(深深地感觉到自己的方法比网上的麻烦....)

  用dp[i]表示当前计数器的值为 i ,还需要掷多少次(期望值)使得游戏结束,那么转移方程是不难列出来的:dp[i] = Sigma(dp[i + j] + 1.0) / total + dp[0] / total,(3<=j<=K1*K2*K3,total = K1*K2*K3),发现每个dp[i]都会衍生出一个含dp[0]的项。

  再详细点:如果我们要算4 2 2 2 1 1 1

  dp[0] = (3 * (dp[4] + 1) + 3 * (dp[5] + 1) + (dp[6] + 1)) / total + (dp[0] + 1) / total(没有dp[3],因为掷到三个1的话,计数器置零)

  dp[4] = (3 * (dp[8] + 1) + 3 * (dp[9] + 1) + (dp[10] + 1)) / total + (dp[0] + 1) / total 

  因为 : dp[5] ~ dp[10] = 0

  所以:  dp[0] = (3 * (dp[4] + 1) + 4) / total + (dp[0] + 1) / total 

         dp[4] = (3 + 3 + 1) / total + (dp[0] + 1) / total

   -->  dp[0] = 【3 *(7 / total + (dp[0] + 1) / total + 1) + 4】/ total + (dp[0] + 1) /total

  发现每一个dp的表达式中都有(dp[0] + 1)这一项,那么我们可以把dp表达式写成dp[i] = A[i] * (dp[0] + 1)+ B[i]

  而A[i]可以由A[i + j](1<=j<=total)求出,B同理....那么可以用记忆化搜索解决。

  由:A[i] = Sigma(A[i + j] + 1) / total , B[i] = (Sigma(B[i + j]) + 1) / total(这个B不太好理解....其实i+j中的A[i+j]代到i中后(A[i + j] * (dp[0] + 1) + 1) / total,会产生1 / total,应记入B[i])

  那么:dp[0] = (A[0] + B[0]) / (1.0 - B[0])

  (当然也可以用递推啦~)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 #define MP(a,b) make_pair(a,b)
 8 typedef pair<long double,long double> pdd;
 9 const int INF = (1 << 30) - 1;
10 
11 int T,n,K1,K2,K3,a,b,c;
12 long double A[550],B[550],total;
13 
14 void Solve(int p){
15     if(A[p] || p > n)    return;
16     long double tmp = 0.0,res = 0.0;
17     for(int i = 1; i <= K1; ++i){
18         for(int j = 1; j <= K2; ++j){
19             for(int k = 1; k <= K3; ++k){
20                 if(i == a && j == b && k == c)    continue;
21                 Solve(p + i + j + k);
22                 res += A[p + i + j + k] + 1.0;
23                 tmp += B[p + i + j + k];
24             }
25         }
26     }
27     A[p] = res / total;
28     B[p] = (tmp + 1.0) / total;
29 }
30 
31 int main(){
32     scanf("%d",&T);
33     while(T--){
34         scanf("%d%d%d%d%d%d%d",&n,&K1,&K2,&K3,&a,&b,&c);
35         memset(A,0,sizeof(A));
36         memset(B,0,sizeof(B));
37         total = (long double)K1 * K2 * K3;
38         Solve(0);
39         printf("%.15Lf\n",(A[0] + B[0]) / (1.0 - B[0]));
40     }
41     return 0;
42 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4199498.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值