HDU 5602 Black Jack(概率DP)

Description
21点又名黑杰克(英文:Blackjack),起源于法国,已流传到世界各地。
21点,是一种使用扑克牌玩的赌博游戏。亦是唯一一种在赌埸中可以在概率中战胜庄家的一种赌博游戏。
———来自好搜百科
我们定义21点的规则如下,和原始规则稍微不一样。
牌点数如下:
A 2 3 4 5 6 7 8 9 10 J Q K
A当成1点
JQK全部当成10点。
我们假设赌场准备了很多副牌,也就是可以假设每次摸到每张牌的概率是一样的。
玩家有两个人,分别为庄家和闲家。
一开始两人都拿两张牌,两个人都可以看到对方的牌。
闲家先操作,每次可以叫牌或者停止叫牌。
如果叫牌,从牌堆中拿一张牌,一旦叫牌后手牌超过21点,直接判输,称为“爆点”,否则一直叫牌直到停止叫牌,轮到庄家。
轮到庄家后,跟闲家一样的叫牌或停止叫牌,一旦爆点也是直接判输。
如果没有爆点,谁点数大就谁赢,点数一样判平。
给你两家的牌,如果闲家胜率>50%输出”YES”,否则输出”NO”
哦,对了,每个人都是绝顶聪明的。
Input
第一行一个数Test(Test<=100000)。表示数据组数。
下面每组数据,一个4字符字符串,前两个字符表示闲家的牌,后两张表示庄家的。
(用T表示10)
Output
对于每组数据输出”YES”或者”NO”,表示闲家是否有50%以上的胜率。
Sample Input
1
TTT9
Sample Output
YES
Solution
用dp[0][i][j]表示闲家当前点数为i,庄家当前点数为j,闲家叫牌时闲家获胜的最大几率(闲家要最大化自身赢率),则得到转移方程
dp[0][i][j]=max{dp[0][i][j],(dp[0][i+1][j]+…+dp[0][i+9][j]+4*dp[0][i+10][j])/13}
用dp[1][i][j]表示闲家当前点数为i,庄家当前点数为j,庄家叫牌时闲家获胜的最小几率(庄家要最小化闲家赢率),则得到转移方程
dp[1][i][j]=min{dp[1][i][j],(dp[1][i][j+1]+…+dp[1][i][j+9]+4*dp[1][i][j+10])/13}
两个分别用记忆化搜索即可
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 33
double dp[2][maxn][maxn];
int vis[2][maxn][maxn];
double dfs1(int a,int b)
{
    if(b>21)return 1;
    if(vis[1][a][b])return dp[1][a][b];
    vis[1][a][b]=1;
    dp[1][a][b]=a>b;
    double temp=0;
    for(int i=1;i<10;i++)temp+=dfs1(a,b+i)/13;
    temp+=dfs1(a,b+10)*4/13;
    return dp[1][a][b]=min(dp[1][a][b],temp);
}
double dfs0(int a,int b)
{
    if(a>21)return 0;
    if(vis[0][a][b])return dp[0][a][b];
    vis[0][a][b]=1;
    dp[0][a][b]=dfs1(a,b);
    double temp=0;
    for(int i=1;i<10;i++)temp+=dfs0(a+i,b)/13;
    temp+=dfs0(a+10,b)*4/13;
    return dp[0][a][b]=max(dp[0][a][b],temp);
}
int get(char c)
{
    if(c=='A')return 1;
    if(c>='0'&&c<='9')return c-'0';
    return 10;
}
int main()
{
    int T;
    char s[5];
    scanf("%d",&T);
    memset(vis,0,sizeof(vis));
    while(T--)
    {
        scanf("%s",s);
        int a=get(s[0])+get(s[1]),b=get(s[2])+get(s[3]);
        double ans=dfs0(a,b);
        if(ans>0.5)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值