zoj 3329 概率dp 求期望

看到网上 http://blog.csdn.net/morgan_xww/article/details/6775853   写的真的好厉害。。我都能看懂。。膜拜一下

dp求期望的题。
题意:
有三个均匀的骰子,分别有k1,k2,k3个面,初始分数是0,
当掷三个骰子的点数分别为a,b,c的时候,分数清零,否则分数加上三个骰子的点数和,
当分数>n的时候结束。求需要掷骰子的次数的期望。
题解:
设 E[i]表示现在分数为i,到结束游戏所要掷骰子的次数的期望值。
显然 E[>n] = 0; E[0]即为所求答案;
E[i] = ∑Pk*E[i+k] + P0*E[0] + 1; (Pk表示点数和为k的概率,P0表示分数清零的概率)
由上式发现每个 E[i]都包含 E[0],而 E[0]又是我们要求的,是个定值。
设 E[i] = a[i]*E[0] + b[i]; 将其带入上面的式子得到:
E[i] = ( ∑Pk*a[i+k] + P0 )*E[0] + ∑Pk*b[i+k] + 1;
显然,
a[i] = ∑Pk*a[i+k] + P0;
b[i] = ∑Pk*b[i+k] + 1;
当 i > n 时:
E[i] = a[i]*E[0] + b[i] = 0;
所以 a[i>n] = b[i>n] = 0;
可依次算出 a[n],b[n]; a[n-1],b[n-1] ... a[0],b[0]; (dp求解a,b)
则 E[0] = b[0]/(1 - a[0]); (此处由E[i] = a[i]*E[0] + b[i]; i=0时得到)


#include<stdio.h>
#include<string.h>
#include<cmath>
#include<algorithm>
using namespace std;
int n,k1,k2,k3,aa,bb,cc;
double a[555],b[555],p[555];
int main(){
	int cas;
	scanf("%d",&cas);
	while(cas--){
		scanf("%d %d %d %d %d %d %d",&n,&k1,&k2,&k3,&aa,&bb,&cc);
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		int k0=k1+k2+k3;
		double p0=1.0/(k1*k3*k2);
		memset(p,0,sizeof(p));
		for(int i=1;i<=k1;i++){
			for(int j=1;j<=k2;j++){
				for(int k=1;k<=k3;k++){
					if(i!=aa||j!=bb||k!=cc){
						p[i+j+k]+=p0;
					}
				}
			}
		}
		for(int i=n;i>=0;i--){
			for(int k=3;k<=k0;k++){
				a[i]+=p[k]*a[i+k];
				b[i]+=p[k]*b[i+k];
			}
			a[i]+=p0;
			b[i]+=1;
		}
		printf("%.15lf\n",b[0]/(1-a[0]));
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值