『数学期望·动态规划』扑克牌

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/89526291

Description

Rainbow把一副扑克牌(54张)随机洗开,倒扣着放成一摞。然后Admin从上往下依次翻开每张牌,每翻开一张黑桃、红桃、梅花或者方块,就把它放到对应花色的堆里去。

Rainbow想问问Admin,得到A张黑桃、B张红桃、C张梅花、D张方块需要翻开的牌的张数的期望值E是多少?

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

由于Admin和Rainbow还在玩扑克,所以这个程序就交给你来写了~

题目大意

有13,13,13,13,1,1的6堆扑克牌;每一可以从中选出一张牌;求到达最终状态下,选择牌数的最小期望值。

题解

这是一个最优值问题,我们可以思考使用 D P DP 来解决这一个问题。

状态: f a , b , c , d , e , f f_{a,b,c,d,e,f} 表示剩下 a a 张黑桃, b b 张红桃, c c 张梅花, d d 张方块,大王的状态,小王的状态的最小期望值。其中 e = 0 e=0 表示没有被选择, 1   2   3   4 1\ 2\ 3\ 4 分别表示选择了黑桃、红桃、梅花和方块。f同理。

目标状态: f 0 , 0 , 0 , 0 , 0 , 0 . f_{0,0,0,0,0,0}.

sum表示总牌

然后就有很复杂的状态转移方程了: f a , b , c , d , e , f = 13 a 54 s u m f a + 1 , b , c , d , e , f + 13 b 54 s u m f a , b + 1 , c , d , e , f + 13 c 54 s u m f a , b , c + 1 , d , e , f f_{a,b,c,d,e,f}=\frac{13-a}{54-sum}*f_{a+1,b,c,d,e,f}+ \frac{13-b}{54-sum}*f_{a,b+1,c,d,e,f}+\frac{13-c}{54-sum}*f_{a,b,c+1,d,e,f} + 13 d 54 s u m f a , b , c , d + 1 , e , f + 1 54 s u m f a , b , c , d , 1 4 , f ( i f   e = 0 ) + 1 54 s u m f a , b , c , d , e , 1 4 ( i f   f = 0 ) +\frac{13-d}{54-sum} *f_{a,b,c,d+1,e,f} +\frac{1}{54-sum}*f_{a,b,c,d,1-4,f}(if\ e=0)+\frac{1}{54}-sum*f_{a,b,c,d,e,1-4}(if\ f=0)

对于实现的方式,我们可以使用记忆化搜索来实现。

有几个需要注意的细节:

  • 无解:如果A,B,C,D中大于十三的总牌数大于2,说明大王和小王补不齐,一定无解。
  • 对于记忆化里的状态:如果所有的牌已经达到要求,返回0即可。

代码如下:

#include<bits/stdc++.h>

using namespace std;

int A,B,C,D;
double F[16][16][16][16][5][5];

double dfs(int a,int b,int c,int d,int e,int f) 
{
	if (F[a][b][c][d][e][f] > 1e-8)  
		return F[a][b][c][d][e][f];
	if (a+(e==1)+(f==1)>=A && b+(e==2)+(f==2)>=B &&
	c+(e==3)+(f==3)>=C && d+(e==4)+(f==4)>=D) return 0;
	double sum,Min1,Min2;
	Min1 = Min2 = 1e9, sum = 1.0;
	int cnt = a+b+c+d+(e!=0)+(f!=0);
	if (a<13) sum += dfs(a+1,b,c,d,e,f)*(13-a)/(54-cnt);
	if (b<13) sum += dfs(a,b+1,c,d,e,f)*(13-b)/(54-cnt);
	if (c<13) sum += dfs(a,b,c+1,d,e,f)*(13-c)/(54-cnt);
	if (d<13) sum += dfs(a,b,c,d+1,e,f)*(13-d)/(54-cnt);
	if (e == 0) for (int i=1;i<5;++i) Min1 = min(Min1,dfs(a,b,c,d,i,f)/(54-cnt));
	if (f == 0) for (int i=1;i<5;++i) Min2 = min(Min2,dfs(a,b,c,d,e,i)/(54-cnt));
	if (e == 0) sum += Min1;
	if (f == 0) sum += Min2;
	return F[a][b][c][d][e][f] = sum;
}

int main(void)
{
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
	cin>>A>>B>>C>>D;
	if (max(A-13,0)+max(B-13,0)+max(C-13,0)+max(D-13,0) > 2) 
		return puts("-1.000"), 0;
	double ans = dfs(0,0,0,0,0,0);
	printf("%.3lf",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/89526291
今日推荐