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 \neq 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\neq 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-sum\le0\),则期望为\(\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;
}

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


猜你喜欢

转载自www.cnblogs.com/pyyyyyy/p/12759030.html
今日推荐