您的位置:首页 > 其它

zoj 3329 One Person Game(概率dp,期望)

2014-07-19 16:10 447 查看
OnePersonGame

TimeLimit:1Second
MemoryLimit:32768KBSpecialJudge

Thereisaverysimpleandinterestingone-persongame.Youhave3dice,namely
Die1,Die2andDie3.Die1has
K1faces.Die2has
K2faces.Die3has
K3faces.Allthedicearefairdice,sotheprobabilityofrollingeachvalue,1to
K1,K2,
K3isexactly1/K1,1/
K2and1/K3.Youhaveacounter,andthegameisplayedasfollow:

Setthecounterto0atfirst.
Rollthe3dicesimultaneously.Iftheup-facingnumberofDie1is
a,theup-facingnumberofDie2isbandtheup-facingnumberof
Die3isc,setthecounterto0.Otherwise,addthecounterbythetotalvalueofthe3up-facingnumbers.

Ifthecounter'snumberisstillnotgreaterthann,gotostep2.Otherwisethegameisended.

Calculatetheexpectationofthenumberoftimesthatyoucastdicebeforetheendofthegame.

Input

Therearemultipletestcases.ThefirstlineofinputisanintegerT(0<
T<=300)indicatingthenumberoftestcases.ThenTtestcasesfollow.Eachtestcaseisalinecontains7non-negativeintegers
n,K1,K2,
K3,a,b,
c(0<=n<=500,1<K1,
K2,K3<=6,1<=
a<=K1,1<=
b<=K2,1<=c<=
K3).

Output

Foreachtestcase,outputtheanswerinasingleline.Arelativeerrorof1e-8willbeaccepted.

SampleInput

2
0222111
0666111

SampleOutput

1.142857142857143
1.004651162790698


题意:有三个骰子,分别有k1,k2,k3个面。
每次掷骰子,如果三个面分别为a,b,c则分数置0,否则加上三个骰子的分数之和。
当分数大于n时结束。求游戏的期望步数。初始分数为0

思路:
设dp[i]表示达到i分时到达目标状态的期望,pk为投掷k分的概率,p0为回到0的概率
则dp[i]=∑(pk*dp[i+k])+dp[0]*p0+1;
都和dp[0]有关系,而且dp[0]就是我们所求,为常数
设dp[i]=A[i]*dp[0]+B[i];
代入上述方程右边得到:
dp[i]=∑(pk*A[i+k]*dp[0]+pk*B[i+k])+dp[0]*p0+1
=(∑(pk*A[i+k])+p0)dp[0]+∑(pk*B[i+k])+1;
明显A[i]=(∑(pk*A[i+k])+p0)
B[i]=∑(pk*B[i+k])+1
先递推求得A[0]和B[0].
那么dp[0]=B[0]/(1-A[0]);[/code]


AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
#include<algorithm>
#definelllonglong
#defineL(rt)(rt<<1)
#defineR(rt)(rt<<1|1)
usingnamespacestd;

constintINF=1e9;
constintmaxn=1000005;
constintmod=20140717;

intn,k1,k2,k3,a,b,c;
doublep[600],A[600],B[600];
intmain()
{
intt;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
doublep0=1.0/k1/k2/k3;
memset(p,0,sizeof(p));
for(inti=1;i<=k1;i++)
for(intj=1;j<=k2;j++)
for(intk=1;k<=k3;k++)
if(i!=a||j!=b||k!=c)
{
p[i+j+k]+=p0;
}
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
for(inti=n;i>=0;i--)
{
A[i]=p0,B[i]=1;
for(intj=1;j<=k1+k2+k3;j++)
{
A[i]+=A[i+j]*p[j];
B[i]+=B[i+j]*p[j];
}
}
printf("%.16f\n",B[0]/(1-A[0]));
}
return0;
}

[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: