LightOJ 1364 Expected Cards 期望DP+记忆化搜索

Expected Cards LightOJ - 1364

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=14 表示已经抽到,代替四种花色之一)对应的期望。

代码如下:

#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;
}

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值