热身赛1——B——Simplified Blackjack

在一次聚会上,Bob打算和Alice一起玩Blackjack游戏,但Alice平时很少玩扑克类游戏,Bob觉得跟Alice解释清楚Blackjack的规则有点困难,于是Bob决定和Alice玩一次简化版的Blackjack。

点数计算
游戏过程使用若干副去掉大小王的扑克牌,A代表1点,2-10即为牌面上的点数,J、Q、K均代表10点。

发牌
游戏包含两位玩家,一位玩家做庄家负责发牌, 另一位玩家为闲家。 发牌时依次派发牌堆最上方的牌。 庄家会向闲家派发一张暗牌(即不被揭开的牌), 然后向自己派发一张暗牌, 接着庄家会向闲家派发一张明牌(即被揭开的牌), 然后又向自己派发一张明牌。 之后庄家会询问闲家是否继续要牌,并以明牌的形式派发。 闲家在看完自己的暗牌和明牌之后决定是否继续要牌。

爆煲
如果闲家要牌后手上拥有的牌的总点数超过21点(俗称爆煲),便要揭开手上所有的牌,算作庄家赢。 如果闲家手上拥有的牌的总点数不超过21点, 该闲家可决定是否继续要牌。 当闲家决定不再要牌后,庄家就必须揭开自己手上所有的牌,然后决定是否继续要牌,直到爆煲或者决定不再要牌为止。 如果庄家爆煲,算作闲家赢。

点数决胜
如果庄家最终没有爆煲,闲家便要揭开手上所有的牌,比较点数决定谁胜谁负。 如果闲家的点数比庄家大,算作闲家赢。 如果闲家的点数和庄家相等或者比庄家小,则算作庄家赢。

现在Bob是庄家,Alice是闲家,在Bob开始发牌的时候Alice借助好朋友Cara的超能力已经知道了牌堆最上方的若干张牌,Alice想知道她是否一定可以赢下这一局呢?

INPUT
输入包含不超过100组数据。 每组数据的第一行为一个整数n(5 ≤ n ≤ 42),即Alice已经知道的牌的数量。 接下来一行包含n个1-13之间的整数,依次描述了牌堆从上至下最上方的n张牌的牌面。 这里我们用整数1代表扑克牌的A,整数11、12、13分别代表扑克牌的J、Q、K。 数据保证这n张牌的总点数不少于42。

OUTPUT

对于每组数据,如果Alice一定可以赢下这一局,输出“Yes”,否则输出“No”。

Sample Input
9
12 5 13 5 2 7 3 1 5
9
5 13 5 5 5 5 1 3 4
5
11 11 11 11 2
8
8 11 9 6 2 3 2 4

Sample Output
Yes
Yes
No
No

说明:

对于第一个样例,Alice手中的暗牌和明牌分别为Q、K,Bob手中的暗牌和明牌分别为5、5。Alice选择不要牌即可,总点数为20,无论Bob接下来要几张牌,Alice都可以赢。

对于第二个样例,Alice手中的暗牌和明牌分别为5、5,Bob手中的暗牌和明牌分别为K、5。Alice可以选择要三张牌,总点数为21,无论Bob接下来要几张牌,Alice都可以赢。Alice也可以选择只要两张牌,总点数为20,同样可以确保赢下这一局。

对于第三个样例,Alice手中的暗牌和明牌分别为J、J,Bob手中的暗牌和明牌分别为J、J。Alice只能选择不要牌,否则会爆煲,总点数为20。此时Bob如果也不要牌,总点数为20,庄家赢。因此Alice不能保证一定可以赢Bob。

对于第四个样例,Alice手中的暗牌和明牌分别为8、9,Bob手中的暗牌和明牌分别为J、6。无论Alice要几张牌,Bob都有可能赢Alice。

哇,这个思维题,看上去确实不难,二十分钟敲出来的代码一直WA,然后就在想是否还有什么情况没考虑到,实在是想不到啊T_T,只能求助大神解析了……
这题的坑在于考虑这样一种情况:Alice手中点数为18,Bob手中点数为14,接下来牌为3,7,如果按照我们最开始的想法,获取能获得的最大值,Alice要了3后不要,点数为21,Bob要了7后不要,点数也为21,这样Alice就输了,但这其实是一个必赢的局面:Alice不要,Bob要了3后仍比Alice小,再要就会爆,Bob必输
因此,我们还有一种选择性放弃的策略,也就是,对任意Alice取牌的情况,都要判断Bob能拿到的最大的牌,这样思路就清晰了。
我们用下一个循环,表示Alice取牌的每种情况

for(i=front;i<n;i++)

再用下一个循环判断bob的最大值

for(k=front;k<n;k++)

就很清晰了
PS:这里我还是卡了好久,因为没看见n张牌的总和不小于42……于是就在判断都拿完还没分出胜负的情况……也是傻了……

include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;

const int maxn=50;

int Queue[maxn];//模拟牌堆

int A;//闲家
int B;//庄家

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0;i<n;i++)
        {
            scanf("%d",&Queue[i]);
            if(Queue[i]>10)Queue[i]=10;
        }
        A=Queue[0]+Queue[2];
        B=Queue[1]+Queue[3];
        int front=4;
        //拿牌过程
        int i;
        for(i=front;i<n;i++)
        {
            //Alice的每一次取牌,都需要考虑Bob以决定是否选择性弃牌
            int tempB=B;
            int k;
            for(k=front;k<n;k++)
            {
                if(tempB+Queue[k]>21)
                    break;
                tempB+=Queue[k];
            }
            if(A>tempB)//if(A>tempB&&k!=n-1),这里就是我在判断全拿完的情况
            {
                printf("Yes\n");
                break;
            }
            else
            {
                A+=Queue[i];
            }
            if(A>21||i==n-1)
            {
                printf("No\n");
                break;
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值