UVa 451 Poker Solitaire Evaluator
题目描述
题目要求评估一个 5×55 \times 55×5 扑克牌方阵中所有行和列的手牌类型。每行 555 张牌组成一手牌,每列 555 张牌也组成一手牌,共 101010 手牌。需要统计每种手牌类型(从低到高)出现的次数。手牌类型(由低到高)为:
- Nothing\texttt{Nothing}Nothing:不符合以下任何类型。
- One Pair\texttt{One Pair}One Pair:一对。
- Two Pair\texttt{Two Pair}Two Pair:两对。
- Three of a Kind\texttt{Three of a Kind}Three of a Kind:三条。
- Straight\texttt{Straight}Straight:顺子(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 等)。
- Flush\texttt{Flush}Flush:同花(五张同花色)。
- Full House\texttt{Full House}Full House:葫芦(三条加一对)。
- Four of a Kind\texttt{Four of a Kind}Four of a Kind:四条。
- 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}Nothing 到 Straight 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 循环问题。
手牌识别逻辑
按照从高到低的顺序判断,一旦匹配即返回对应类型:
- 同花顺:同时满足同花和顺子。
- 四条:有 444 张牌点数相同。
- 葫芦:有 333 张牌点数相同且另外 222 张点数相同。
- 同花:555 张牌花色相同。
- 顺子:点数按顺序连续,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 等)。
- 三条:有 333 张牌点数相同。
- 两对:有两个不同点数各出现 222 次。
- 一对:有一个点数出现 222 次。
- 高牌:以上均不满足。
顺子判断
由于点数字符不连续(如 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,且点数计数分布为 333 和 222。
四条判断
点数种类数为 222,且点数计数分布为 444 和 111。
实现方法
- 将 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;
}
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)