AcWing 218. 扑克牌

根据书上的提示这是一道数学期望和动态规划结合的题目

扑克牌是由各种花色各(13)张+带小王组成的,总共由(54)张牌组成

(f[a][b][c][d][x][y])表示已经拿到了(a)张黑桃,(b)张红桃,(c)张梅花,(d)张方块,小王和大王的状态分别是(x,y)其中(x=0)表示放到黑桃里,(1)表示放到红桃里,(2)表示放到梅花里,(3)表示放到方块里,(4)则表示没有拿到((y)同理)的期望翻开次数

我们可以通过计算轻松获得到当前的翻到的牌的数量:(sum=a+b+c+d+(x==4)+(y==4))

(update):上面写错了,应该是(x!=4和y!=4),淦

剩下的牌的数量是(Sum=54-sum)

现在事情变得通透了起来,淦

以黑桃为例,剩余黑桃的数量为(13-a),那么下一张牌翻到黑桃的概率就是(frac{13-a}{Sum}(Sum eq 0))

那么对答案的贡献就是(frac{13-a}{Sum}*f[a+1][b][c][d][x][y])(反着来递推)

其他的花色类似,这里就不在赘述了

再来看带小王的情况

特殊地,如果翻开的牌是大王或者小王,(Admin)将会把它作为某种花色的牌放入对应堆中,使得放入之后(E)的值尽可能小。

我们还是按照上面花色的分析思路,以小王为例

剩余的小王数量就是(1-(x==4)),剩余的牌的数量仍是(Sum)

显然抽到小王的概率就是(frac{1-(x==4)}{Sum}(Sum eq 0)),貌似只有当(x=4)的情况才有贡献,所有不用考虑其他情况,淦

如果抽到小王,我们把它作为某种花色的牌放入对应堆中,使得放入之后E的值尽可能小。

所以小王的贡献就是(frac{1}{Sum}min_{0 le i le 3}{f[a][b][c][d][i][y]})

大王情况类似,这里就不在赘述了

综上转移方程就是

[f[a][b][c][d][x][y]=frac{13-a}{Sum}*f[a+1][b][c][d][x][y]+frac{13-b}{Sum}*f[a][b+1][c][d][x][y]+frac{13-c}{Sum}*f[a][b][c+1][d][x][y]+frac{13-d}{Sum}*f[a][b][c][d+1][x][y]+min_{0 le i le 3}{f[a][b][c][d][i][y]}(x==4)+min_{0 le j le3}{f[a][b][c][d][x][j]}(y==4) ]

边界问题:

  • 如果已经翻开的牌的数量答案的题目的要求,则期望为(0),例如(a+(x==0)+(y==0))

    • 注意这个条件应该是所有翻开的牌都满足,就是说条件使用&&链接的,淦
  • (54)张牌被翻完但是仍无法到岸,即(54-sumle0),则期望为(infty)

目标:

(f[0][0][0][0][4][4])

#include<bits/stdc++.h>
using namespace std;
const int N=15;
double f[N][N][N][N][5][5];
int v[N][N][N][N][5][5];
int A,B,C,D;
double solve(int a,int b,int c,int d,int x,int y)
{
	if(v[a][b][c][d][x][y]) return f[a][b][c][d][x][y];
	v[a][b][c][d][x][y]=1;
	if(a+(x==0)+(y==0)>=A&&b+(x==1)+(y==1)>=B&&c+(x==2)+(y==2)>=C&&d+(x==3)+(y==3)>=D) return 0;
	double sum=1.0;
	int cnt=a+b+c+d+(x!=4)+(y!=4);
	if(a<13) sum+=solve(a+1,b,c,d,x,y)*(13-a)/(54-cnt);
	if(b<13) sum+=solve(a,b+1,c,d,x,y)*(13-b)/(54-cnt);
	if(c<13) sum+=solve(a,b,c+1,d,x,y)*(13-c)/(54-cnt);
	if(d<13) sum+=solve(a,b,c,d+1,x,y)*(13-d)/(54-cnt);
	if(x==4)
	{
		double minn1=1e9;
		for(int i=0;i<=3;++i) minn1=min(minn1,solve(a,b,c,d,i,y)/(54-cnt));
		sum+=minn1;
	}
	if(y==4)
	{
		double minn2=1e9;
		for(int j=0;j<=3;++j) minn2=min(minn2,solve(a,b,c,d,x,j)/(54-cnt));
		sum+=minn2;
	}
	return f[a][b][c][d][x][y]=sum;
}
int main()
{
	cin>>A>>B>>C>>D;
	if(max(A-13,0)+max(B-13,0)+max(C-13,0)+max(D-13,0)>2){
		puts("-1.000");
		return 0;
	}
	double ans=solve(0,0,0,0,4,4);
	printf("%.3f",ans);
	return 0;
}

[写题一时爽,调题火葬场 ]


原文地址:https://www.cnblogs.com/pyyyyyy/p/12759030.html