#P3198. 德州扑克(200分)
-
1000ms
Tried: 83
Accepted: 28
Difficulty: 5
所属公司 :
华为od
德州扑克(200分)
题面描述
五张牌,每张牌由牌大小和花色组成,牌大小包括 2 ~ 10、J、Q、K、A,牌花色为红桃(H)、黑桃(S)、梅花(C)、方块(D)四种花色之一。
判断牌型的规则如下:
- 同花顺(牌型1):同一花色的顺子,例如红桃2、红桃3、红桃4、红桃5、红桃6。
- 四条(牌型2):四张相同数字加一张单牌,例如红桃A、黑桃A、梅花A、方块A加黑桃K。
- 葫芦(牌型3):三张相同数字加一对,例如红桃5、黑桃5、梅花5加方块9、梅花9。
- 同花(牌型4):所有牌同一花色,例如方块3、方块7、方块10、方块J、方块Q。
- 顺子(牌型5):五张牌按照连续大小排列,花色不必相同,例如红桃2、黑桃3、红桃4、红桃5、方块6。
- 三条(牌型6):三张相同数字加两张单牌。
说明:
- 五张牌中不会出现大小和花色完全相同的牌。
- 牌型编号越小,牌型等级越高,例如同花顺(1)比四条(2)高。
- 包含 A 的合法顺子仅有 10、J、Q、K、A 和 A、2、3、4、5,如 K、A、2、3、4 不视为顺子。
思路
要判断五张牌的牌型,需要按照牌型优先级从高到低进行判断。具体步骤如下:
-
解析输入:将每张牌的大小和花色分别存储起来。需要将牌大小转换为数值,以便于比较和排序。特别需要处理 A,因为它可以作为 1 或 14 来参与顺子判断。
-
统计牌大小和花色:
- 统计每种牌大小出现的次数。
- 统计每种花色出现的次数。
-
判断同花顺(牌型1):
- 所有牌的花色相同。
- 牌大小构成顺子。
-
判断四条(牌型2):
- 存在一个牌大小出现四次。
-
判断葫芦(牌型3):
- 存在一个牌大小出现三次,另一个牌大小出现两次。
-
判断同花(牌型4):
- 所有牌的花色相同。
-
判断顺子(牌型5):
- 牌大小构成顺子。
-
判断三条(牌型6):
- 存在一个牌大小出现三次,剩下两张牌大小不相同。
如果符合多个牌型,选择编号最小的牌型。
顺子的判断需要考虑 A 的特殊情况,即 A 可以作为 1 或 14。因此,需要对牌大小进行排序,并检查是否存在连续的五个数。
cpp
#include <bits/stdc++.h>
using namespace std;
// 将牌大小转换为数值
int cardValue(const string &s) {
if (s == "J") return 11;
if (s == "Q") return 12;
if (s == "K") return 13;
if (s == "A") return 14;
return stoi(s);
}
int main(){
vector<pair<int, char>> cards;
// 读取五张牌
for(int i=0;i<5;i++){
string num;
char suit;
cin >> num >> suit;
int val = cardValue(num);
cards.emplace_back(val, suit);
}
// 统计牌大小的频率
unordered_map<int, int> count_map;
// 统计花色的频率
unordered_map<char, int> suit_map;
for(auto &p : cards){
count_map[p.first]++;
suit_map[p.second]++;
}
// 提取所有牌的数值并排序
vector<int> vals;
for(auto &p : cards){
vals.push_back(p.first);
}
sort(vals.begin(), vals.end());
// 检查顺子
bool is_straight = true;
for(int i=1;i<5;i++) {
if(vals[i] != vals[i-1] +1){
is_straight = false;
break;
}
}
// 特殊情况 A,2,3,4,5
bool is_straight_low = false;
if(vals[4] == 14){
vector<int> low_vals = vals;
low_vals[4] = 1;
sort(low_vals.begin(), low_vals.end());
is_straight_low = true;
for(int i=1;i<5;i++) {
if(low_vals[i] != low_vals[i-1] +1){
is_straight_low = false;
break;
}
}
}
bool has_straight = is_straight || is_straight_low;
// 检查同花
bool is_flush = false;
for(auto &[s, cnt] : suit_map){
if(cnt ==5){
is_flush = true;
break;
}
}
// 判断牌型
// 牌型1:同花顺
if(is_flush && has_straight){
cout << "1";
return 0;
}
// 判断四条和葫芦,需要分析牌大小的频率
vector<int> freq;
for(auto &[k, v] : count_map){
freq.push_back(v);
}
sort(freq.begin(), freq.end(), greater<int>());
// 牌型2:四条
bool four_kind = false;
for(auto &f : freq){
if(f ==4){
four_kind = true;
break;
}
}
if(four_kind){
cout << "2";
return 0;
}
// 牌型3:葫芦
bool full_house = false;
if(freq.size() >=2){
if(freq[0] ==3 && freq[1] >=2){
full_house = true;
}
}
if(full_house){
cout << "3";
return 0;
}
// 牌型4:同花
if(is_flush){
cout << "4";
return 0;
}
// 牌型5:顺子
if(has_straight){
cout << "5";
return 0;
}
// 牌型6:三条
bool three_kind = false;
if(freq[0] ==3){
three_kind = true;
}
if(three_kind){
cout << "6";
return 0;
}
// 若不符合任何牌型,理论上不会出现
cout << "-1";
return 0;
}
python
# 将牌大小转换为数值
def card_value(s):
if s == 'J':
return 11
elif s == 'Q':
return 12
elif s == 'K':
return 13
elif s == 'A':
return 14
else:
return int(s)
# 读取五张牌
cards = []
for _ in range(5):
num, suit = input().split()
val = card_value(num)
cards.append( (val, suit) )
# 统计牌大小和花色的频率
from collections import defaultdict
count_map = defaultdict(int)
suit_map = defaultdict(int)
for val, suit in cards:
count_map[val] +=1
suit_map[suit] +=1
# 提取并排序牌的数值
vals = sorted([val for val, _ in cards])
# 检查顺子
is_straight = True
for i in range(1,5):
if vals[i] != vals[i-1] +1:
is_straight = False
break
# 特殊情况 A,2,3,4,5
is_straight_low = False
if vals[-1] ==14:
low_vals = vals.copy()
low_vals[-1] =1
low_vals.sort()
is_straight_low = True
for i in range(1,5):
if low_vals[i] != low_vals[i-1] +1:
is_straight_low = False
break
has_straight = is_straight or is_straight_low
# 检查同花
is_flush = False
for cnt in suit_map.values():
if cnt ==5:
is_flush = True
break
# 判断牌型
# 牌型1:同花顺
if is_flush and has_straight:
print(1)
exit()
# 统计频率并排序
freq = sorted(count_map.values(), reverse=True)
# 牌型2:四条
if 4 in freq:
print(2)
exit()
# 牌型3:葫芦
if len(freq) >=2 and freq[0]==3 and freq[1]>=2:
print(3)
exit()
# 牌型4:同花
if is_flush:
print(4)
exit()
# 牌型5:顺子
if has_straight:
print(5)
exit()
# 牌型6:三条
if 3 in freq:
print(6)
exit()
# 若不符合任何牌型,理论上不会出现
print(-1)
java
import java.util.*;
public class Main {
// 将牌大小转换为数值
public static int cardValue(String s){
switch(s){
case "J": return 11;
case "Q": return 12;
case "K": return 13;
case "A": return 14;
default: return Integer.parseInt(s);
}
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
List<int[]> cards = new ArrayList<>();
// 读取五张牌
for(int i=0;i<5;i++){
String num = sc.next();
char suit = sc.next().charAt(0);
int val = cardValue(num);
cards.add(new int[]{val, suit});
}
// 统计牌大小和花色的频率
Map<Integer, Integer> countMap = new HashMap<>();
Map<Character, Integer> suitMap = new HashMap<>();
for(int[] card : cards){
countMap.put(card[0], countMap.getOrDefault(card[0], 0) +1);
char suit = (char)card[1];
suitMap.put(suit, suitMap.getOrDefault(suit, 0)+1);
}
// 提取并排序牌的数值
List<Integer> vals = new ArrayList<>();
for(int[] card : cards){
vals.add(card[0]);
}
Collections.sort(vals);
// 检查顺子
boolean isStraight = true;
for(int i=1;i<5;i++){
if(vals.get(i) != vals.get(i-1)+1){
isStraight = false;
break;
}
}
// 特殊情况 A,2,3,4,5
boolean isStraightLow = false;
if(vals.get(4) ==14){
List<Integer> lowVals = new ArrayList<>(vals);
lowVals.set(4, 1);
Collections.sort(lowVals);
isStraightLow = true;
for(int i=1;i<5;i++){
if(lowVals.get(i) != lowVals.get(i-1)+1){
isStraightLow = false;
break;
}
}
}
boolean hasStraight = isStraight || isStraightLow;
// 检查同花
boolean isFlush = false;
for(int cnt : suitMap.values()){
if(cnt ==5){
isFlush = true;
break;
}
}
// 判断牌型
// 牌型1:同花顺
if(isFlush && hasStraight){
System.out.println(1);
return;
}
// 统计频率并排序
List<Integer> freq = new ArrayList<>(countMap.values());
freq.sort(Collections.reverseOrder());
// 牌型2:四条
if(freq.contains(4)){
System.out.println(2);
return;
}
// 牌型3:葫芦
if(freq.size() >=2 && freq.get(0)==3 && freq.get(1)>=2){
System.out.println(3);
return;
}
// 牌型4:同花
if(isFlush){
System.out.println(4);
return;
}
// 牌型5:顺子
if(hasStraight){
System.out.println(5);
return;
}
// 牌型6:三条
if(freq.contains(3)){
System.out.println(6);
return;
}
// 若不符合任何牌型,理论上不会出现
System.out.println(-1);
}
}
题目内容
五张牌,每张牌由牌大小和花色组成,牌大小 2 ~ 10、J、Q、K、A,牌花色为红桃、黑桃、梅花、方块四种花色之一。
判断牌型:
牌型 1 ,同花顺:同一花色的顺子,如红桃2红桃3红桃4红桃5红桃6。
牌型 2 ,四条:四张相同数字 + 单张,如红桃A黑桃A梅花A方块A + 黑桃K。
牌型 3 ,葫芦:三张相同数字 + 一对,如红桃5黑桃5梅花5 + 方块9梅花9。
牌型 4 ,同花:同一花色,如方块3方块7方块10方块J方块Q。
牌型 5 ,顺子:花色不一样的顺子,如红桃2黑桃3红桃4红桃5方块6。
牌型 6 ,三条:三张相同+两张单。
说明:
五张牌里不会出现牌大小和花色完全相同的牌 编号小的牌型较大,如同花顺比四条大,依次类推。 包含 A 的合法的顺子只有 10 J Q K A 和 A 2 3 4 5 ;类似 K A 2 3 4 的序列不认为是顺子。
输入描述
输入由 5 行组成,每行为一张牌大小和花色,牌大小为 2 ~ 10、J、Q、K、A ,花色分别用字符H、S、C、D 表示红桃、黑桃、梅花、方块。
输出描述
输出牌型序号, 5 张牌符合多种牌型时,取最大的牌型序号输出。
样例1
输入
4 H
5 S
6 C
7 D
8 D
输出
5
说明
4 5 6 7 8 构成顺子,输出 5
样例2
输入
9 S
5 S
6 S
7 S
8 S
输出
1
说明
既是顺子又是同花,输出 1 ,同花顺