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; }
ZOJ 3329 One Person Game (概率dp),布布扣,bubuko.com
ZOJ 3329 One Person Game (概率dp)
原文:http://blog.csdn.net/bolininahuaalex/article/details/24198535