UVA451 题解

· · 题解

题目描述

本题单测试点有多组数据,在每组数据中...

要求对每一组数据的 10 组牌,求出这些牌型各出现了多少次。

分析

本题的关键是如何判断这 9 种牌型。根据题目描述,不难看出本题的关键是需要:

由于输入的点数和花色全部是字符形式,因此可以使用 map<char,int> 类型的容器来进行统计。由于需要判断构不构成顺子,而是这一点和牌的顺序无关,因此可以采用一个 set<char> 容器存储五张牌的点数(会自动去重),如果容器的元素数量(利用成员函数 size 获取)为 5 并且是连号,就是顺子。参考代码:

map<char, int> pointCnt, categoryCnt;
set<char> point, category;

至于顺子的情况,可以直接打表枚举。参考代码:

const set<char> straight[13] = {
    {'A','2','3','4','5'},{'2','3','4','5','6'},{'3','4','5','6','7'},{'4','5','6','7','8'},{'5','6','7','8','9'},
    {'6','7','8','9','X'},{'7','8','9','X','J'},{'8','9','X','J','Q'},{'9','X','J','Q','K'},{'X','J','Q','K','A'},
    {'J','Q','K','A','2'},{'Q','K','A','2','3'},{'K','A','2','3','4'} };

对于给定的 5 张牌而言:

  1. 若只有两种不同点数的牌(即上述 map 容器的 size 等于 2),就对 map 容器内的元素遍历,如果发现 map 中的某种点数的牌出现了 4 次,就能判定为“四条”,某种点数的牌出现 3 次即为“三带一对”,根据题意,相应地返回 87

  2. 若出现了 3 种不同点数的牌,则进一步遍历 map 元素,若某种点数的牌出现 3 次即为“三张”,出现 2 次即为“两对”,相应的返回 43

  3. 若出现了 4 种不同点数的牌,容易看出只可能是“一对”,返回 2

  4. 若出现了 5 种不同点数的牌,就需要通过和上述的 straight[13] 列表比对判定是否为“顺子”,再通过花色的集合的元素数量判断是否为同花。若为同花顺,返回 9。若为普通顺子,返回 5。若为同花,返回 6。其余情况为散牌,返回 1

综上所述即为全部 9 种情况的判定方法。由于我们已经按照题意用 19 的返回值来表示这些牌型,因此可以使用一个长度为 10 的整数数组来存储每种牌型出现的次数,输出即可。需要说明的是:

  1. 输出时,逗号的后面有一个空格,最后一个数后面不能输出多余的逗号;

  2. 相邻两组数据之间要输出一个空行,最后一组数据完毕后不能输出多余的空行,因此处理多组数据时需要判断当前是不是最后一组数据。

完整代码

#include<iostream>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
const set<char> straight[13] = {
    {'A','2','3','4','5'},{'2','3','4','5','6'},{'3','4','5','6','7'},{'4','5','6','7','8'},{'5','6','7','8','9'},
    {'6','7','8','9','X'},{'7','8','9','X','J'},{'8','9','X','J','Q'},{'9','X','J','Q','K'},{'X','J','Q','K','A'},
    {'J','Q','K','A','2'},{'Q','K','A','2','3'},{'K','A','2','3','4'} };
//分析手牌, 返回值1-9分别表示散牌、1对、2对、3张、顺子、同花、三带一对、四条、同花顺
int cardAnalysis(string* c)
{
    map<char, int> pointCnt, categoryCnt;
    set<char> point, category;
    for (int i = 0; i <= 4; i += 1)
    {
        pointCnt[c[i][0]] += 1;
        categoryCnt[c[i][1]] += 1;
        point.insert(c[i][0]);
        category.insert(c[i][1]);
    }
    if (pointCnt.size() == 2) //2种不同的点数
    {
        for (auto it = pointCnt.begin(); it != pointCnt.end(); it++)
        {
            if (it->second == 4) return 8; //四条
            else if (it->second == 3) return 7; //三带一对
        }
    }
    else if (pointCnt.size() == 3) //3种不同点数
    {
        for (auto it = pointCnt.begin(); it != pointCnt.end(); it++)
        {
            if (it->second == 3) return 4; // 三张
            else if (it->second == 2) return 3; //2对
        }
    }
    else if (pointCnt.size() == 4) return 2;
    else if (categoryCnt.size() == 1) //只有同一种花色的牌
    {
        for (int i = 0; i <= 12; i += 1) if (point == straight[i]) return 9; //同花顺
        return 6; //同花
    }
    else if (categoryCnt.size() >= 2) //大于等于2种花色的牌
    {
        for (int i = 0; i <= 12; i += 1) if (point == straight[i]) return 5; //顺子
        return 1;//散牌
    }
    return 0; //这个return 0是用来避免编译器报警告的
}

void solve(void)
{
    string card[5][5];
    for (int i = 0; i <= 4; i += 1) for (int j = 0; j <= 4; j += 1) cin >> card[i][j];
    int cnt[10] = { 0 };
    for (int i = 0; i <= 4; i += 1)
    {
        cnt[cardAnalysis(card[i])] += 1;
        string tmp[5] = { card[0][i],card[1][i],card[2][i],card[3][i],card[4][i] };
        cnt[cardAnalysis(tmp)] += 1;
    }
    for (int i = 1; i <= 9; i += 1)
    {
        printf("%d", cnt[i]);
        if (i != 9) printf(", ");
    }
    putchar(10);
}

int main()
{
    int n;
    cin >> n;
    while (n)
    {
        solve();
        if (n != 1) putchar(10);
        n -= 1;
    }
}