hdu 5602 Black Jack

36 篇文章 0 订阅
4 篇文章 0 订阅

传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=5602

题意:
21点游戏,A当成1,JQK全部当成10点,轮流叫牌,爆点直接判输,假设牌数特别多,且每个人拿到每张牌的概率是一样的!!
一开始二者都有张牌为输入!问最后闲家胜率大于50%的概率!!!!!! 

明显的概率dp,用记忆化搜搜去写嘛!!!
两个dfs分别模拟闲家和庄家叫牌时的情况,终止条件是庄家叫牌,用dp[i,j]表示闲家现有牌定数和为i,庄家为j,时获胜的概率,那么显然就有
dp[i,j]+=1/13*dp[i+(1~9),j]+4/13*dp[10~K,j]
那么对于庄家而言,如果当前i<=j那么dp值直接为0,否则j要继续往上加,然后就是正常的去判断一下就ok了!!!

这题很邪门,写的时候各种乱,最后还因为初始化的时候直接1到maxn wrong了,真应该注意这一点,注意本题应该开两个dp数组,分别表示该谁取得时候获胜的概率,如果要是只开一个的话,因为庄家在暂时失败的时候是可以继续取获胜的,而开一个数组地话则不能实现这一点!!!

哦哦,原来是我考虑错了,我之前想的是
dfs2应该有2种终止状态,但实际上只有1种,即a<=b的话,res就为0;否则的话,肯定要继续取。。。。是等于1收尾的时候想错了,等于1的情况只有是当目前a>b,然后现在应该b继续取但是取爆点了的情况,对对,就是这样去想的,只有这一种情况才能导致闲家最后获胜,这也提醒了我一点,在思考问题的时候,就应该顺着一个人的角度去想,否则的话很容易就想乱了,最后导致各种逻辑错误

还有应该注意的就是,这种dp两个状态一定要开两份,分别表示当前是谁来取,获胜的概率,否则是记录不下来的!!!!

本题还有应该注意的的地方就是,概率初始化的时候应该取为-1,概率有可能为0,这种状态因为已经计算过了,所以一定要记录下来,所以说初始化应该为-1,然后判断条件是>-eps!!!!

注意是一直叫牌直到停牌,即不是选择叫还是不叫,如果当前还是暂时输,可以一直叫下去,所以这样递归写就非常合情合理了!!!

code:

#include<bits/stdc++.h>
using namespace std;
int t;char s[100];int sum1,sum2;
const int maxn=33;
const double eps=1e-8;
double dp1[maxn][maxn],dp2[maxn][maxn];
int get(char s){
    if(s=='A') return 1;
    if(s=='T'||s=='J'||s=='Q'||s=='K') return 10;
    return s-'0';
}
double dfs2(int a,int b){
    double &res=dp2[a][b];
    if(res>-eps) return res;
    if(a<=b) return res=0.0;
//  if(a>b||b>21) return res=1.0;
    res=0.0;
    for(int i=1;i<=9;i++){
       if(b+i<=21)
        res+=(dfs2(a,b+i)/13);
       else res+=1.0/13;
    }
    for(int i=1;i<=4;i++){
      if(b+10<=21)
        res+=(dfs2(a,b+10)/13);
      else res+=1.0/13;
    }
    return res;
}
double dfs(int a,int b){
    double &res=dp1[a][b];
    if(res>-eps) return res;
    if(a>21) return res=0.0;
    res=0.0;
    for(int i=1;i<=9;i++){
        res+=(dfs(a+i,b)/13);
    }
    for(int i=1;i<=4;i++){
        res+=(dfs(a+10,b)/13);
    }
    res=max(res,dfs2(a,b));
    return res;
}
int main(){     
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);sum1=0;sum2=0;
        sum1=get(s[0])+get(s[1]);
        sum2=get(s[2])+get(s[3]);
        for(int i=1;i<maxn;i++){
            for(int j=1;j<maxn;j++){
                dp1[i][j]=-1.0;dp2[i][j]=-1.0;
            }
        }
        if(dfs(sum1,sum2)-0.5>eps) puts("YES");
        else puts("NO");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值