(ACW218)扑克牌(数学期望)

题意:

Rainbow 把一副扑克牌(54张)随机洗开,倒扣着放成一摞。然后 Admin 从上往下依次翻开每张牌,每翻开一张黑桃、红桃、梅花或者方块,就把它放到对应花色的堆里去。Rainbow 想问问 Admin,得到 A 张黑桃、B 张红桃、C 张梅花、D 张方块需要翻开的牌的张数的期望值 E 是多少?特殊地,如果翻开的牌是大王或者小王,Admin 将会把它作为某种花色的牌放入对应堆中,使得放入之后 E 的值尽可能小。

分析:设f[x][y][z][w][p][q],表示已经翻开了x张黑桃,y张红桃,z张梅花,w张方块,并且小王的状态为p,大王的状态为q时的期望值。p=0代表没有抽到小王,p=1、2、3、4,分别代表将小王视作黑桃、红桃、梅花、方块。大王的记录方法同理。

当前已经翻开的牌的总数为sum=x+y+z+w+(p!=0)+(q!=0),那么剩余牌的数目就是54-sum,那么下次抽取到的牌为黑桃的概率就是(13-x)/(54-sum),其余花色同理,如果大王或者小王当前还没有被抽到,那么下次被抽到的概率就是1/(54-sum),注意要对大小王进行分类讨论,使得当大小王放入某花色堆时总期望尽量小,递推公式不大好打,我写到了纸上:

待求状态为f[0][0][0][0][0][0],直接利用记忆化搜索进行求解就好。

在数学期望递推、数学期望动态规划中,我们通常把终止状态(翻开的牌数达到要求)作为初值,把起始状态(尚未翻开任何牌)作为目标,倒着进行计算。这是因为在很多情况下,起始状态是唯一的(0,0,0,0,0,0),而终止状态却有很多(只要各花色翻开的牌数都足够即可)。

下面是代码: 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
#define INF 1e20
const int N= 15;
double f[N][N][N][N][5][5];
int A,B,C,D;
double dp(int x,int y,int z,int w,int p,int q)
{
	//a,b,c,d分别为当前已经翻开的黑桃,红桃,梅花,方块的张数 
	int a=x+(p==1)+(q==1);
	int b=y+(p==2)+(q==2);
	int c=z+(p==3)+(q==3);
	int d=w+(p==4)+(q==4);
	if(f[x][y][z][w][p][q]) return f[x][y][z][w][p][q];
	if(a>=A&&b>=B&&c>=C&&d>=D) return 0;
	int sum=54-a-b-c-d;
	double ans=0;
	if(x<13) ans+=1.0*(13-x)/sum*(dp(x+1,y,z,w,p,q)+1);
	if(y<13) ans+=1.0*(13-y)/sum*(dp(x,y+1,z,w,p,q)+1);
	if(z<13) ans+=1.0*(13-z)/sum*(dp(x,y,z+1,w,p,q)+1);
	if(w<13) ans+=1.0*(13-w)/sum*(dp(x,y,z,w+1,p,q)+1);
	if(p==0)//小王放置各堆中的期望最小值 
	{
		double t=INF;
		for(int i=1;i<=4;i++)
			t=min(t,1.0/sum*(dp(x,y,z,w,i,q)+1));
		ans+=t;
	}
	if(q==0)//大王放置各堆中的期望最小值 
	{
		double t=INF;
		for(int i=1;i<=4;i++)
			t=min(t,1.0/sum*(dp(x,y,z,w,p,i)+1));
		ans+=t;
	}
	return f[x][y][z][w][p][q]=ans;
}
int main()
{
	scanf("%d%d%d%d",&A,&B,&C,&D);
	int t=0;
	if(A>13) t+=A-13; 
	if(B>13) t+=B-13; 
	if(C>13) t+=C-13; 
	if(D>13) t+=D-13; 
	if(t>2)	puts("-1.000");
	else printf("%.3lf",dp(0,0,0,0,0,0));
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值