有 54 54 54 张牌,其中♣ ♦ ♥ ♠ 各有 13 13 13 张,还有两张大小王,现在从洗好的牌里依次抽,问抽到至少 C C C 张梅花, D D D 张方片, H H H 张红桃, S S S 张黑桃所需要抽的期望张数是多少?假如抽到大小王的话,可以令他们为任意的花色,但是必须立刻指定他们的花色,不能随后更改。
用 d p [ c ] [ d ] [ h ] [ s ] [ i ] [ j ] dp[c][d][h][s][i][j] dp[c][d][h][s][i][j] 表示当前抽到的四个花色数量分别是 c , d , h , s c,d,h,s c,d,h,s 时,并且小王大王分别处于 i , j i,j i,j 状态时( i = 0 i=0 i=0表示还未抽到, i = 1 ∼ 4 i=1\sim 4 i=1∼4 表示已经抽到,代替四种花色之一)对应的期望。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
//#define WINE
#define INF 0x3f3f3f3f
using namespace std;
int T,iCase,a[5],b[5];
double res,dp[14][14][14][14][5][5];
bool check(int c,int d,int h,int s,int p,int q){
memset(b,0,sizeof(b));
b[1]=c;b[2]=d;b[3]=h;b[4]=s;b[p]++;b[q]++;
for(int i=1;i<=4;i++)
if(b[i]<a[i])return false;
return true;
}
double dfs(int c,int d,int h,int s,int p,int q){
if(check(c,d,h,s,p,q))return dp[c][d][h][s][p][q]=0;
if(dp[c][d][h][s][p][q]>=0)return dp[c][d][h][s][p][q];
int sum=54-c-d-h-s;
if(p)sum--;if(q)sum--;
if(sum==0)return 0;
double res=0;
if(c<13)res+=dfs(c+1,d,h,s,p,q)*(13-c)/sum;
if(d<13)res+=dfs(c,d+1,h,s,p,q)*(13-d)/sum;
if(h<13)res+=dfs(c,d,h+1,s,p,q)*(13-h)/sum;
if(s<13)res+=dfs(c,d,h,s+1,p,q)*(13-s)/sum;
if(!p){
double tmp=INF;
for(int i=1;i<=4;i++)
tmp=min(tmp,dfs(c,d,h,s,i,q));
res+=tmp/sum;
}
if(!q){
double tmp=INF;
for(int i=1;i<=4;i++)
tmp=min(tmp,dfs(c,d,h,s,p,i));
res+=tmp/sum;
}
return dp[c][d][h][s][p][q]=res+1;
}
int main(){
#ifdef WINE
freopen("data.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&a[1],&a[2],&a[3],&a[4]);
int tmp=0;
for(int i=1;i<=4;i++)tmp+=max(0,a[i]-13);
if(tmp>2){
printf("Case %d: -1\n",++iCase);
continue;
}
memset(dp,-1,sizeof(dp));
res=dfs(0,0,0,0,0,0);
printf("Case %d: %.8lf\n",++iCase,res);
}
return 0;
}