zoj 3329 One Person Game (概率与期望DP)

本文解析了一道关于三个骰子的经典概率与期望DP题目。通过详细的数学推导,介绍了如何利用概率DP解决这类问题,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

传送门

题目大意:有3个筛子,分别有k1,k2,k3面,掷出每一面的概率相同。如果掷出a,b,c那么分数归零,否则分数+(a+b+c),问达到分数n的期望步数。

题解:概率与期望DP

非常经典的题目,一般针对这种成环的题,可以用高斯消元来求解。但是因为这道题只会回到n,所以我们可以通过列式子,画式子巧妙的求解。

dp[i]=sigma(j=1..k1+k2+k3)p[j]*dp[i+j]+dp[0]*p[0]+1

设dp[0]=A[0]*dp[0]+1

对应的我们将上面所有的式子多转换成dp[i]=A[i]*dp[0]+B[i]的形式

那么转移的式子就变成了:

dp[i]=sigma(j=1..k1+k2+k3)p[j]*(A[j+i]*dp[0]+B[j+i])  +dp[0]*p[0] +1

合并同类项

dp[i]=(sigma(j=1..k1+k2+k3)p[j]*A[j+i] +p[0])*dp[0]+ sigma(j=1..k1+k2+k3)p[j]*B[j+i]+1

A[i]=(sigma(j=1..k1+k2+k3)A[j+i]*p[j] +p[0]) B[i]=sigma(j=1..k1+k2+k3)B[j+i]*p[j]+1

这样我们就可以逆推A[i],B[i]

那么最后的答案就是B[0]/(1-A[0])

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 503
using namespace std;
int n,a,b,c,k1,k2,k3,T;
double A[N],B[N],p[N];
int main()
{
	freopen("a.in","r",stdin);
	scanf("%d",&T);
	while (T--) {
		scanf("%d%d%d%d%d%d%d",&n,&k1,&k2,&k3,&a,&b,&c);
		double p0=1.0/k1/k2/k3; 
		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!=a||j!=b||k!=c) p[i+j+k]+=p0;
		memset(A,0,sizeof(A));
		memset(B,0,sizeof(B));
		for (int i=n;i>=0;i--) {
			A[i]=p0; 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("%.16lf\n",B[0]/(1.0-A[0]));
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值