UVA451 题解
0x00AC3375 · · 题解
题目描述
本题单测试点有多组数据,在每组数据中...
-
会输入一个
5\times 5 的字符串矩阵,每个字符串包含两个字符。 -
每个字符串的第一个字符表示一张扑克牌的点数和花色,
A,2~9,X,J,Q,K分别表示扑克牌的13 种点数,第二个字符的S,H,C,D表示黑桃、红桃、梅花和方块四种花色。 -
上述这个矩阵的五行五列构成了
10 个含有5 张牌的牌组,每一组的5 张牌可能是散牌、一对、两对、三张、顺子、同花、三带一对、四条(俗称炸弹)、同花顺这9 种不同的牌型(没错,就是 1989 年的电影《赌神》里的玩法)。
要求对每一组数据的
分析
本题的关键是如何判断这
-
统计一组牌(
5 张牌)出现了几种不同的花色; -
统计一组牌中出现了多少种不同的点数;
-
判断这五张牌是不是连着的(构成顺子)。
由于输入的点数和花色全部是字符形式,因此可以使用 map<char,int> 类型的容器来进行统计。由于需要判断构不构成顺子,而是这一点和牌的顺序无关,因此可以采用一个 set<char> 容器存储五张牌的点数(会自动去重),如果容器的元素数量(利用成员函数 size 获取)为
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'} };
对于给定的
-
若只有两种不同点数的牌(即上述
map容器的size等于2 ),就对map容器内的元素遍历,如果发现map中的某种点数的牌出现了4 次,就能判定为“四条”,某种点数的牌出现3 次即为“三带一对”,根据题意,相应地返回8 或7 ; -
若出现了
3 种不同点数的牌,则进一步遍历map元素,若某种点数的牌出现3 次即为“三张”,出现2 次即为“两对”,相应的返回4 或3 ; -
若出现了
4 种不同点数的牌,容易看出只可能是“一对”,返回2 ; -
若出现了
5 种不同点数的牌,就需要通过和上述的straight[13]列表比对判定是否为“顺子”,再通过花色的集合的元素数量判断是否为同花。若为同花顺,返回9 。若为普通顺子,返回5 。若为同花,返回6 。其余情况为散牌,返回1 。
综上所述即为全部
-
输出时,逗号的后面有一个空格,最后一个数后面不能输出多余的逗号;
-
相邻两组数据之间要输出一个空行,最后一组数据完毕后不能输出多余的空行,因此处理多组数据时需要判断当前是不是最后一组数据。
完整代码
#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;
}
}