ZOJ 332j One Person Game [Expected dp]

Main idea of the title:

There are three dices, k1, K2 and K3 sides respectively.
For each roll of dice, if the three sides are a, B and c, the score is set to zero, otherwise the sum of the scores of the three dices is added.
It ends when the score is greater than n. Find the expected number of steps in the game. The initial score is 0.

Ideas for problem solving:

At the beginning, the score of 0 was regarded as no bonus, and WA spent half a day.

Let dp[i] denote the expectation that I has reached the target state in time-sharing, p[j] is the probability of throwing J points and p[0] is the probability of returning to zero.
dp[i]=∑(dp[i+j]∗p[j])+dp[0]∗p[0]+1;

Because each step is related to the unknown quantity dp[0], the dp[i] of each step can not be obtained immediately, so it seems that the simultaneous equations are eliminated by Gauss elimination.
But because each step is related to the unknown quantity dp[0], and is a first-order equation, each dp[i] can be transformed into the form of A[i]*dp[0]+B[i], that is:
dp[i]=A[i]∗dp[0]+B[i]

When substituted for the original form, then:
dp[i]=∑(p[j]∗(A[i+j]∗dp[0]+B[i+j]))+dp[0]∗p[0]+1

Simplify
dp[i]=(∑(p[j]∗A[i+j])+p[0])∗dp[0]+∑(p[j]∗B[i+j])+1

So get
A[i]=∑(p[j]∗A[i+j])+p[0]
B[i]=∑(p[j]∗B[i+j])+1

So we can first reckon A[i], B[i]. Finally, dp[0]=B[0]/(1-A[i]).

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-')f=-1,c=getchar();
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}

const int N=1000;
int T,n,k1,k2,k3,k,a,b,c;
double A[N],B[N],p[N];

int main()
{
    //freopen("lx.in","r",stdin);
    //freopen("lx.out","w",stdout);
    T=getint();
    while(T--)
    {
        memset(p,0,sizeof(p));
        memset(A,0,sizeof(A));
        memset(B,0,sizeof(B));
        n=getint();
        k1=getint(),k2=getint(),k3=getint();
        a=getint(),b=getint(),c=getint();
        p[0]=1.0/(k1*k2*k3);
        for(int i=1;i<=k1;i++)
            for(int j=1;j<=k2;j++)
                for(int k=1;k<=k3;k++)
                    if(i!=a||j!=b||k!=c)
                        p[i+j+k]+=p[0];
        for(int i=n;i>=0;i--)
        {
            A[i]=p[0],B[i]=1;
            for(int j=1;j<=k1+k2+k3;j++)
            {
                A[i]+=p[j]*A[i+j];
                B[i]+=p[j]*B[i+j];
            }
        }   
        printf("%0.15lf\n",B[0]/(1-A[0]));      
    }
    return 0;
}

Posted by simonj on Sat, 09 Feb 2019 01:42:17 -0800