题目描述

题目要求评估一个 5×55 \times 55×5 扑克牌方阵中所有行和列的手牌类型。每行 555 张牌组成一手牌,每列 555 张牌也组成一手牌,共 101010 手牌。需要统计每种手牌类型(从低到高)出现的次数。手牌类型(由低到高)为:

  1. Nothing\texttt{Nothing}Nothing:不符合以下任何类型。
  2. One Pair\texttt{One Pair}One Pair:一对。
  3. Two Pair\texttt{Two Pair}Two Pair:两对。
  4. Three of a Kind\texttt{Three of a Kind}Three of a Kind:三条。
  5. Straight\texttt{Straight}Straight:顺子(A\texttt{A}A 可循环,如 A,2,3,4,5\texttt{A,2,3,4,5}A,2,3,4,5J,Q,K,A,2\texttt{J,Q,K,A,2}J,Q,K,A,2 等)。
  6. Flush\texttt{Flush}Flush:同花(五张同花色)。
  7. Full House\texttt{Full House}Full House:葫芦(三条加一对)。
  8. Four of a Kind\texttt{Four of a Kind}Four of a Kind:四条。
  9. Straight Flush\texttt{Straight Flush}Straight Flush:同花顺。

每种手牌只按其最高类型计数(如四条不计为两对或三条)。

输入格式

第一行一个整数 NNN,表示测试用例的数量,后面跟一个空行。每个测试用例包含 555 行,每行 555 张牌,牌之间用空格分隔。每张牌由两个字符组成:第一个字符为点数(A,2,3,4,5,6,7,8,9,X,J,Q,K\texttt{A,2,3,4,5,6,7,8,9,X,J,Q,K}A,2,3,4,5,6,7,8,9,X,J,Q,K),第二个字符为花色(S,H,D,C\texttt{S,H,D,C}S,H,D,C)。两个连续测试用例之间由一个空行分隔。

输出格式

对于每个测试用例,输出一行,包含 999 个整数,表示每种手牌类型出现的次数,从 Nothing\texttt{Nothing}NothingStraight Flush\texttt{Straight Flush}Straight Flush,用逗号和空格分隔。两个连续测试用例的输出之间由一个空行分隔。

样例

输入

1

AS 2S 3S 4S 5S
AC 2H 3H 5C 4C
AH 2D KC KH 5D
AD 3D KD 9D 8D
XH 3C XC XS 8C

输出

1, 1, 2, 1, 1, 1, 1, 1, 1

题目分析

本题的核心是识别 555 张牌的手牌类型。需要处理顺子中的 A\texttt{A}A 循环问题。

手牌识别逻辑

按照从高到低的顺序判断,一旦匹配即返回对应类型:

  1. 同花顺:同时满足同花和顺子。
  2. 四条:有 444 张牌点数相同。
  3. 葫芦:有 333 张牌点数相同且另外 222 张点数相同。
  4. 同花555 张牌花色相同。
  5. 顺子:点数按顺序连续,A\texttt{A}A 可视为最小(A,2,3,4,5\texttt{A,2,3,4,5}A,2,3,4,5)或最大(J,Q,K,A,2\texttt{J,Q,K,A,2}J,Q,K,A,2 等)。
  6. 三条:有 333 张牌点数相同。
  7. 两对:有两个不同点数各出现 222 次。
  8. 一对:有一个点数出现 222 次。
  9. 高牌:以上均不满足。

顺子判断

由于点数字符不连续(如 8,9,X,J,Q\texttt{8,9,X,J,Q}8,9,X,J,Q),需要将点数映射为数值以便判断。一种方法是预定义顺子字符串 "23456789XJQKA2345"\texttt{"23456789XJQKA2345"}"23456789XJQKA2345",包含所有可能的顺子序列(长度为 555)。检查 ranks\texttt{ranks}ranks 集合(点数集合)是否包含其中某个连续子串的所有字符。注意 A\texttt{A}A 可以出现在开头(作为最小)或结尾(作为最大),因此字符串中 A\texttt{A}A 出现两次。

同花判断

检查所有牌的花色是否相同(即花色集合大小为 111)。

葫芦判断

点数种类数为 222,且点数计数分布为 333222

四条判断

点数种类数为 222,且点数计数分布为 444111

实现方法

  • 5×55 \times 55×5 的牌阵读入 5×55 \times 55×5 的二维数组。
  • 构造 101010 手牌:前 555 手为行,后 555 手为列。
  • 对每手牌调用识别函数,累加计数。
  • 输出 999 个计数。

复杂度分析

每手牌只需常数时间判断,总复杂度 O(10)O(10)O(10)

代码实现

// Poker Solitaire Evaluator
// UVa ID: 451
// Verdict: Accepted
// Submission Date: 2016-07-20
// UVa Run Time: 0.070s
//
// 版权所有(C)2016,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>
using namespace std;

const int NOTHING = 1, ONE_PAIR = 2, TWO_PAIR = 3, THREE_KIND = 4, STRAIGHT = 5, FLUSH = 6, FULL_HOUSE = 7, FOUR_KIND = 8, STRAIGHT_FLUSH = 9;
    
int findHand(vector<string>& cards) {
    map<char, int> ranks;
    set<char> suits;
    vector<int> sequence;

    for (int i = 0; i < 5; i++) {
        ranks[cards[i].front()]++;
        suits.insert(cards[i].back());
    }
    for (auto pair : ranks) sequence.push_back(pair.second);
   
    // straight flush
    // AC 2C 3C 4C 5C, TC JC QC KC AC, JC QC KC AC 2C are straight flush
    bool is_straight = false;
    string straight = "23456789XJQKA2345";
    for (int i = 0; i <= straight.length() - 5; i++) {
        is_straight = true;
        for (int j = i; j <= i + 4; j++)
            if (ranks.find(straight[j]) == ranks.end()) {
                is_straight = false;
                break;
            }
        if (is_straight) break;
    }
    bool is_flush = (suits.size() == 1);
    if (is_straight && is_flush) return STRAIGHT_FLUSH;

    // four of a kind
    bool four_kind = *max_element(sequence.begin(), sequence.end()) >= 4;
    if (four_kind) return FOUR_KIND;

    // full house
    bool is_full_house = (ranks.size() == 2 && accumulate(sequence.begin(), sequence.end(), int(0)) == 5);
    if (is_full_house) return FULL_HOUSE;

    // flush
    if (is_flush) return FLUSH;

    // straight
    if (is_straight) return STRAIGHT;

    // three of a kind
    bool three_kind = *max_element(sequence.begin(), sequence.end()) >= 3;
    if (three_kind) return THREE_KIND;

    // two pair
    bool is_two_pair = ranks.size() == 3;
    if (is_two_pair) return TWO_PAIR;

    // one pair
    bool is_one_pair = *max_element(sequence.begin(), sequence.end()) >= 2;
    if (is_one_pair) return ONE_PAIR;

    // nothing
    return NOTHING;
}

int main() {
    cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
    int cases;
    vector<int> hands(10);
    vector<vector<string>> cards(10, vector<string>(5));
    cin >> cases;
    for (int c = 1; c <= cases; c++) {
        if (c > 1) cout << '\n';
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
                cin >> cards[i][j];
        for (int i = 5, j = 0; i < 10; i++, j++)
            for (int k = 0; k < 5; k++)
                cards[i][k] = cards[k][j];
        fill(hands.begin(), hands.end(), 0);
        for (int i = 0; i < 10; i++) hands[findHand(cards[i])]++;
        for (int j = 1; j <= 9; j++) {
            if (j > 1) cout << ", ";
            cout << hands[j];
        }
        cout << '\n';
    }
    return 0;
}
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐