扑克牌 题解

扑克牌 题解

题意

$ $ 有一副扑克牌共 (54) 张,包括黑桃、红桃、梅花和方块四种花色各 (13) 张与 (2) 张大小王。将这副牌反面朝上放置,每次翻一张牌,若翻到大小王可以将其视作任何花色。求最后翻出 (A) 张黑桃、(B) 张红桃、(C) 张梅花和 (D) 张方块的最小期望翻牌次数是多少。


题解

(~~~~) 计黑桃为第一种花色,红桃为第二种花色,梅花为第三种花色,方块为第四种花色。

(~~~~) 一道定义为入门期望DP的题,虽然我当时想了挺久。

(~~~~) 显然DP至少会定义四个维度表示四种花色拥有的张数。考虑如何处理大小王。

(~~~~) 因此定义 (dp_{a,b,c,d,x,y}) ,表示翻开 (a) 张黑桃、(b) 张红桃、(c) 张梅花、(d) 张方块,且小王用作第 (x) 种花色,大王用作第 (y) 种花色后凑到要求的种类的期望翻牌最小张数。当 (x=0) 时表示未翻开小王, (y=0) 时表示为翻开大王。

(~~~~) 考虑一个已知的 (dp_{a,b,c,d,x,y}) 能扩展出哪些状态。

(~~~~) 以黑桃为例,当你有 (a) 张黑桃,已经翻开 (k) 张牌时,有 (dfrac{13-a}{54-k}) 的概率再翻出一张黑桃。

(~~~~) 今天学到了一个结论,当某事件发生的概率为 (p) 时,则其期望在 (dfrac{1}{p}) 次实验后第一次出现该事件。具体可以看 知乎上一个回答 (蒟蒻的我只会用结论)。所以就会在期望 (dfrac{54-k}{13-a}) 次翻牌后第一次翻到一张黑桃。所以当你再翻出来一张黑桃时,状态就变成了 (dp_{a+1,b,c,d,x,y}) 。由期望的性质 (operatorname{E(XY)=E(X) imes E(Y)}) 可以得到 (dp_{a+1,b,c,d,x,y}) 一定有贡献来自 (dp_{a,b,c,d,x,y} imes dfrac{54-k}{13-a}) .另外三种花色也是同理。

(~~~~) 再来考虑双王的问题,若一个状态 (dp_{a,b,c,d,0,y}) ,此时小王未被翻出来,因此已经翻开 (k) 张牌时,有 (dfrac{1}{54-k}) 的概率翻出小王。我们按照上面的方式化简,得到 (dp_{a,b,c,d,x,y}) 也有来自 (dp_{a,b,c,d,0,y} imes (54-k)) 的贡献,其中 (xin[1,4])

(~~~~) 再来考虑初始状态,可以发现当四种花色及双王满足条件时,其 (dp) 值为 (0) ,而要求的答案就是 (dp_{0,0,0,0,0,0}) ,因此本题是逆推。

(~~~~) 既然如此,则每个 (dp_{a,b,c,d,x,y}) 一定依托于多翻一张牌的状态。将上面所有式子移项即可。当考虑双王时,可以得到 (dfrac{dp_{a,b,c,d,x,y}}{54-k} (1le xle 4)) 都有可能是 (dp_{a,b,c,d,0,y}) 的一部分加数。因为求最小期望,我们取四个值得最小值即可。

(~~~~) 综上,本题的DP转移方程是 :

[Large dp_{a,b,c,d,x,y}= dp_{a+1,b,c,d,x,y} imes dfrac{13-a}{54-sum} +dp_{a,b+1,c,d,x,y} imes dfrac{13-b}{54-sum} +dp_{a,b,c+1,d,x,y} imes dfrac{13-c}{54-sum} +dp_{a,b,c,d+1,x,y} imes dfrac{13-d}{54-sum} +min^{4}_{x=1}{ dfrac{dp_{a,b,c,d,x,y}}{54-sum}} imes[x=0] +min^{4}_{y=1}{ dfrac{dp_{a,b,c,d,x,y}}{54-sum}} imes[y=0] +1 ]

(~~~~) 当然,每次转移前要先判断 (a+1),(b+1) 等的值是否合法。

(~~~~) 实现的话记忆化搜索比打递推要方便一些,这里就打的记忆化搜索。


代码

#include <cstdio>
#include <algorithm>
#define f0 dp[a][b][c][d][x][y]
#define f1 dfs(a+1,b,c,d,x,y)
#define f2 dfs(a,b+1,c,d,x,y)
#define f3 dfs(a,b,c+1,d,x,y)
#define f4 dfs(a,b,c,d+1,x,y)
using namespace std;
double dp[15][15][15][15][5][5];
int A,B,C,D;
inline bool check(int a,int b,int c,int d,int x,int y)
{
	if(a+(x==1)+(y==1)>=A&&b+(x==2)+(y==2)>=B&&c+(x==3)+(y==3)>=C&&d+(x==4)+(y==4)>=D) return true;
	else return false;
}
double dfs(int a,int b,int c,int d,int x,int y)
{
	if(f0) return f0;
	if(check(a,b,c,d,x,y)) return 0;
	int sum=a+b+c+d+(x!=0)+(y!=0);
	double cnt=1;
	if(a<13) cnt+=f1*(13-a)/(54-sum);
	if(b<13) cnt+=f2*(13-b)/(54-sum);
	if(c<13) cnt+=f3*(13-c)/(54-sum);
	if(d<13) cnt+=f4*(13-d)/(54-sum);
	if(x==0) 
	{
		double tmp=1000;
		for(int i=1;i<=4;i++) tmp=min(tmp,dfs(a,b,c,d,i,y)/(54-sum));
		cnt+=tmp;
	}
	if(y==0)
	{
		double tmp=1000;
		for(int i=1;i<=4;i++) tmp=min(tmp,dfs(a,b,c,d,x,i)/(54-sum));
		cnt+=tmp;
	}
	return dp[a][b][c][d][x][y]=cnt;
}
int main() {
	scanf("%d %d %d %d",&A,&B,&C,&D);
	if(max(0,A-13)+max(0,B-13)+max(0,C-13)+max(0,D-13)>2)
	{
		printf("-1.000");
		return 0;
	}
	double ans=dfs(0,0,0,0,0,0);
	printf("%.3lf",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Azazel/p/13498697.html