#概率和数学期望,动态规划,记忆化搜索#CH 3803 扑克牌

#概率和数学期望,动态规划,记忆化搜索#CH 3803 扑克牌


分析

首先很容易发现这是一道动态规划的题目,然后设f[a][b][c][d][p][q]f[a][b][c][d][p][q]表示abcdpq01234抽a张黑桃,b张红桃,c张梅花,d张方块,并把小王作为花色p,大王作为花色q,(花色0表示还没有抽,1、2、3、4分别表示黑桃、红桃、梅花、方块)的期望值,那么f[a][b][c][d][p][q]=13a54sumf[a+1][b][c][d][p][q]+13b54sumf[a][b+1][c][d][p][q]+13c54sumf[a][b][c+1][d][p][q]+13d54sumf[a][b][c][d+1][p][q]+min{154sumf[a][b][c][d][14][q]}+min{154sumf[a+1][b][c][d][p][14]}f[a][b][c][d][p][q]=\frac{13-a}{54-sum}f[a+1][b][c][d][p][q]+\frac{13-b}{54-sum}f[a][b+1][c][d][p][q]+\frac{13-c}{54-sum}f[a][b][c+1][d][p][q]+\frac{13-d}{54-sum}f[a][b][c][d+1][p][q]+min\{\frac{1}{54-sum}f[a][b][c][d][1\sim4][q]\}+min\{\frac{1}{54-sum}f[a+1][b][c][d][p][1\sim4]\},答案是f[0][0][0][0][0][0]f[0][0][0][0][0][0],当翻开的牌达到已知量边界为0


代码

#include <cstdio>
#define rr register
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
double f[15][15][15][15][5][5],ans; int t1,t2,t3,t4;
double dp(int a,int b,int c,int d,int p,int q){
	if (f[a][b][c][d][p][q]) return f[a][b][c][d][p][q];//记忆化搜索
	rr double &ans=f[a][b][c][d][p][q]; ans=0;
	rr int x1=a,x2=b,x3=c,x4=d;
	if (p==1) ++x1; if (p==2) ++x2; if (p==3) ++x3; if (p==4) ++x4;
	if (q==1) ++x1; if (q==2) ++x2; if (q==3) ++x3; if (q==4) ++x4;
	if (x1>=t1&&x2>=t2&&x3>=t3&&x4>=t4) return 0;//达到目标
	rr int cnt=54-x1-x2-x3-x4;
	if (cnt<=0) return ans=1e10;//不可能的状态
	if (a<13) ans+=dp(a+1,b,c,d,p,q)*(13-a)/cnt;
	if (b<13) ans+=dp(a,b+1,c,d,p,q)*(13-b)/cnt;
	if (c<13) ans+=dp(a,b,c+1,d,p,q)*(13-c)/cnt;
	if (d<13) ans+=dp(a,b,c,d+1,p,q)*(13-d)/cnt;
	if (!p){
		double t=dp(a,b,c,d,1,q);
		t=min(t,dp(a,b,c,d,2,q));
		t=min(t,dp(a,b,c,d,3,q));
		t=min(t,dp(a,b,c,d,4,q));
		ans+=t/cnt;
	}
	if (!q){
		double t=dp(a,b,c,d,p,1);
		t=min(t,dp(a,b,c,d,p,2));
		t=min(t,dp(a,b,c,d,p,3));
		t=min(t,dp(a,b,c,d,p,4));
		ans+=t/cnt;
	}
	return ++ans;
}
signed main(){
	scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
	ans=dp(0,0,0,0,0,0);
	if (ans>=1e10) ans=-1;
	printf("%.3lf",ans);
}