您的位置:首页 > 其它

ZOJ 3329 One Person Game (概率dp)

2014-04-20 22:00 477 查看
OJ题目:click here~~

题目分析: 有一个计数器 , 初值为0。三个骰子 ,分别有k1, k2, k3面,每个骰子,每面向上的概率相等。给三个数a , b , c。 游戏如下:1,计数器初值设为0。  2,同时掷三个骰子,如果骰子1出现a , 骰子2出现b, 骰子3出现c, 则将计数器设为0,否则将三个数字的和加到计数器上。3,如果此时计数器的数字仍然不超过n , 则回到第2步 , 否则游戏结束。求游戏结束前掷骰子的次数的期望。

设dp[ i ] 为计数器上的数字为 i 时 ,离目标状态的期望步数。显然dp[ 0 ] 是要求的值。

则 dp[ i ] = p0*dp[ 0 ] + sigma dp[ i + k]*p[ k ] + 1,  k 从 3 到(k1 + k2 + k3)---------  1

由式子1可知,dp[ i ] 由dp[ 0 ] 表示 , 而dp[ 0 ] 是我们要求的 ,则将dp[ i + k] 也用dp[ 0] 表示。

设:dp[ i ]  = a[ i ] * dp[ 0 ] + b[ i ] ---------- 2

将2式带入1 , dp[ i ] = p0*dp[ 0 ] + sigma (a[ i + k] * dp[ 0 ] + b[ i + k])*p[ k ] + 1

整理可得:dp[ i ] = (sigma a[ i + k]*p[ k ] + p0 )*dp[ 0 ] + sigma b[ i  + k]*p[ k ] + 1 -----------3

对比3式和1式 , 可得:

a[ i ] =  sigma a[ i + k]*p[ k ] + p0 

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

又当i > n , dp[ i ]  = 0 , 由2式 , 可得
a[ i ]  =  b[ i ] = 0; 


至此,可按i 从大到小 , 求出a[ n ] , b [ n] --- ---- ---- a[ 0 ] , b[ 0 ];

最后由2式 ,
dp[ 0 ] = b[ 0 ] / (1 - a[ 0 ]) ;


AC_CODE

double p[38];
int main()
{
//freopen("in.txt","r",stdin);
int t;
cin >> t;
while(t--){
int n , k1, k2, k3 , aa, bb , cc;
cin >> n >> k1 >> k2 >> k3 >> aa >> bb >> cc;
memset(p , 0 , sizeof(p));
double a[536] = {0};
double b[536] = {0};
double p0 = 1.0/(k1*k2*k3);
int i , j , k;
for(i = 1;i <= k1;i++)
for(j = 1;j <= k2;j++)
for(k = 1;k <= k3;k++)
if(i == aa && j == bb && k == cc) continue;
else p[i + j + k] += p0;
for(i = n;i >= 0;i--){
for(k = 3;k <= (k1+k2+k3);k++){
a[i] += p[k]*a[i+k];
b[i] += p[k]*b[i+k];
}
a[i] += p0;
b[i] += 1;
}
double ans = b[0] / (1 - a[0]);
printf("%.15lf\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: