码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ 3329 One Person Game:期望dp【关于一个点成环——分离系数】

时间:2017-09-23 21:23:50      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:game   stream   分数   read   题目   problem   step   nbsp   mem   

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

题意:

  给你面数分别为k1,k2,k3的三个骰子。

  给定a,b,c三个整数。

  三个骰子每扔一次,若骰子朝上的点数分别为a,b,c,则分数清零,否则当前分数+=骰子点数之和。

  当分数 > n时游戏结束。

  问你扔骰子次数的期望。

 

题意:

  表示状态:

    dp[i] = rest steps

    (当前分数为i时,剩余步数的期望)

 

  找出答案:

    ans = dp[0]

    刚开始分数为0。

 

  如何转移:

    由于此题中可以由高分数转移到低分数,所以转移存在环。

    一般有环dp用高斯消元做。

 

    但是,此题的所有环都跟dp[0]有关,也就是说所有的转移都能写成形如 dp[i] = a[i]*dp[0] + b[i] 的形式(分离系数)。

    那么求出a[0]和b[0]就可以行了,答案为dp[0] = b[0] / (1-a[0])。

 

    (1)dp[i] = sigma(dp[i+k]*p[k]) + dp[0]*p[0] + 1 (原转移方程,p[i]为扔出点数为i的概率,p[0]为扔出(a,b,c)的概率)

    (2)dp[i] = a[i]*dp[0] + b[i] (假设的)

    将(2)代入(1):

      dp[i] = sigma( (a[i+k]*dp[0] + b[i+k]) * p[k] ) + dp[0]*p[0] + 1

      dp[i] = sigma( a[i+k]*dp[0]*p[k] + b[i+k]*p[k] ) + dp[0]*p[0] + 1

      dp[i] = ( sigma(a[i+k]*p[k]) + p[0] )*dp[0] + sigma(b[i+k]*p[k]) + 1

    系数对应相等:

      a[i] = sigma(a[i+k]*p[k]) + p[0]

      b[i] = sigma(b[i+k]*p[k]) + 1

    递推求出a[i] & b[i]即可,求的时候要保证i <= n(有意义)。

    dp[0] = b[0] / (1-a[0])。

 

AC Code:

  1 // state expression:
  2 // dp[i] = rest steps
  3 // i: present score
  4 //
  5 // find the answer:
  6 // ans = dp[0]
  7 //
  8 // transferring:
  9 // 1) dp[i] = sigma(dp[i+k]*p[k]) + dp[0]*p[0] + 1
 10 // 2) dp[i] = a[i]*dp[0] + b[i]
 11 // ***solve:
 12 // dp[i] = sigma( (a[i+k]*dp[0] + b[i+k]) * p[k] ) + dp[0]*p[0] + 1
 13 // dp[i] = sigma( a[i+k]*dp[0]*p[k] + b[i+k]*p[k] ) + dp[0]*p[0] + 1
 14 // dp[i] = ( sigma(a[i+k]*p[k]) + p[0] )*dp[0] + sigma(b[i+k]*p[k]) + 1
 15 // ***result:
 16 // a[i] = sigma(a[i+k]*p[k]) + p[0]
 17 // b[i] = sigma(b[i+k]*p[k]) + 1
 18 // ***run:
 19 // cal a[i] & b[i]
 20 // dp[0] = b[0] / (1-a[0])
 21 //
 22 // boundary:
 23 // set a,b = 0
 24 #include <iostream>
 25 #include <stdio.h>
 26 #include <string.h>
 27 #define MAX_N 505
 28 #define MAX_K 40
 29 
 30 using namespace std;
 31 
 32 int n,t;
 33 int k1,k2,k3;
 34 int e1,e2,e3;
 35 double p[MAX_K];
 36 double a[MAX_N];
 37 double b[MAX_N];
 38 double dp[MAX_N];
 39 
 40 void read()
 41 {
 42     cin>>n>>k1>>k2>>k3>>e1>>e2>>e3;
 43 }
 44 
 45 void cal_pro()
 46 {
 47     memset(p,0,sizeof(p));
 48     p[0]=1.0/(k1*k2*k3);
 49     for(int i=1;i<=k1;i++)
 50     {
 51         for(int j=1;j<=k2;j++)
 52         {
 53             for(int k=1;k<=k3;k++)
 54             {
 55                 if(i!=e1 || j!=e2 || k!=e3)
 56                 {
 57                     p[i+j+k]+=p[0];
 58                 }
 59             }
 60         }
 61     }
 62 }
 63 
 64 void cal_const()
 65 {
 66     memset(a,0,sizeof(a));
 67     memset(b,0,sizeof(b));
 68     for(int i=n;i>=0;i--)
 69     {
 70         for(int k=1;k<=k1+k2+k3;k++)
 71         {
 72             if(i+k>n) break;
 73             a[i]+=a[i+k]*p[k];
 74             b[i]+=b[i+k]*p[k];
 75         }
 76         a[i]+=p[0];
 77         b[i]+=1.0;
 78     }
 79 }
 80 
 81 void solve()
 82 {
 83     cal_pro();
 84     cal_const();
 85     dp[0]=b[0]/(1.0-a[0]);
 86 }
 87 
 88 void print()
 89 {
 90     printf("%.15f\n",dp[0]);
 91 }
 92 
 93 int main()
 94 {
 95     cin>>t;
 96     while(t--)
 97     {
 98         read();
 99         solve();
100         print();
101     }
102 }

 

ZOJ 3329 One Person Game:期望dp【关于一个点成环——分离系数】

标签:game   stream   分数   read   题目   problem   step   nbsp   mem   

原文地址:http://www.cnblogs.com/Leohh/p/7582314.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!