题解
题面描述
斗地主起源于湖北十堰房县,据说是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的,如今已风靡整个中国,并流行于互联网上。
牌型:单顺,又称顺子,最少 5 张牌,最多 12 张牌 (3…A) 不能有 2,也不能有大小王,不计花色。
例如:
- 3−4−5−6−7−8
- 7−8−9−10−J−Q
- 3−4−5−6−7−8−9−10−J−Q−K−A
可用的牌: $3 < 4 < 5 < 6 < 7 < 8 < 9 < 10 < J < Q < K < A < 2 < B(小王) < C(大王)$,每种牌除大小王外有四种花色(共有 13×4+2=54 张牌)。
思路
- 牌面表示:
- 将牌面转化为数字表示,便于比较和排序。按照给定的顺序,3 到 A 分别对应 0 到 11,2 对应 12,小王和大王分别对应 13 和 14。由于顺子不能包含 2、小王和大王,因此有效牌面范围为 0 到 11。
- 计算剩余牌:
- 总牌数为每种牌4张(不包括大小王),需要从总牌中减去手中持有的牌和已出过的牌,得到剩余对手可能持有的牌。
- 统计牌面:
- 统计剩余牌中每种牌的数量。如果某种牌的剩余数量大于0,说明对手可能持有该牌。
- 寻找最长顺子:
- 遍历从 3 到 A 的所有可能的连续序列。
- 对于每一个可能的起始点,尝试尽可能延长顺子的长度,确保每张牌至少存在一张。
- 记录所有可能的顺子,选择最长的那个。如果有多个长度相同的顺子,选择牌面最大的。
- 输出结果:
- 根据找到的最长顺子输出对应的牌面,如果无法找到符合条件的顺子,输出 NO-CHAIN。
python
# 牌面到数字的映射
card_map = {
"3":0, "4":1, "5":2, "6":3, "7":4,
"8":5, "9":6, "10":7, "J":8, "Q":9,
"K":10, "A":11, "2":12, "B":13, "C":14
}
# 数字到牌面的映射
num_to_card = ["3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"]
def main():
import sys
hand = sys.stdin.readline().strip()
played = sys.stdin.readline().strip()
# 初始化牌的总数量
total_cards = [4]*13 + [1,1] # 0-12为3-2,13和14为大小王
# 统计手牌
for card in hand.split('-'):
if card in card_map:
total_cards[card_map[card]] -=1
# 统计已出牌
for card in played.split('-'):
if card in card_map:
total_cards[card_map[card]] -=1
# 构建剩余牌的存在性,仅考虑3到A(0到11)
available = [total_cards[i]>0 for i in range(12)] # 0到11对应3到A
max_len = 0
max_end = -1
for start in range(0, 12-4):
if not available[start]:
continue
current = start
length =1
while current +1 <12 and available[current+1]:
current +=1
length +=1
if length >=5:
if length > max_len or (length == max_len and current > max_end):
max_len = length
max_end = current
if max_len >=5:
start = max_end - max_len +1
chain = '-'.join(num_to_card[i] for i in range(start, max_end+1))
print(chain)
else:
print("NO-CHAIN")
if __name__ == "__main__":
main()
java
import java.util.*;
public class Main {
// 牌面到数字的映射
static Map<String, Integer> cardMap = new HashMap<>();
static String[] numToCard = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"};
static {
String[] cards = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"};
for(int i=0;i<cards.length;i++) {
cardMap.put(cards[i], i);
}
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String hand = sc.next();
String played = sc.next();
// 初始化牌的总数量
int[] totalCards = new int[15];
for(int i=0;i<13;i++) totalCards[i] =4;
totalCards[13] =1; // 小王
totalCards[14] =1; // 大王
// 统计手牌
String[] handCards = hand.split("-");
for(String card: handCards){
if(cardMap.containsKey(card))
totalCards[cardMap.get(card)]--;
}
// 统计已出牌
String[] playedCards = played.split("-");
for(String card: playedCards){
if(cardMap.containsKey(card))
totalCards[cardMap.get(card)]--;
}
// 构建剩余牌的存在性,仅考虑3到A(0到11)
boolean[] available = new boolean[12];
for(int i=0;i<12;i++) {
available[i] = (totalCards[i] >0);
}
// 寻找最长顺子
int maxLen =0;
int maxEnd = -1;
for(int start=0; start <= 11-4; start++){
if(!available[start]) continue;
int current = start;
int len =1;
while(current +1 <12 && available[current+1]){
current++;
len++;
}
if(len >=5){
if(len > maxLen || (len == maxLen && current > maxEnd)){
maxLen = len;
maxEnd = current;
}
}
}
if(maxLen >=5){
int start = maxEnd - maxLen +1;
StringBuilder sb = new StringBuilder();
for(int i=start;i<=maxEnd;i++){
sb.append(numToCard[i]);
if(i != maxEnd) sb.append("-");
}
System.out.println(sb.toString());
}
else{
System.out.println("NO-CHAIN");
}
}
}
cpp
#include <bits/stdc++.h>
using namespace std;
// 牌面到数字的映射
unordered_map<string, int> card_map = {
{"3",0}, {"4",1}, {"5",2}, {"6",3}, {"7",4},
{"8",5}, {"9",6}, {"10",7}, {"J",8}, {"Q",9},
{"K",10}, {"A",11}, {"2",12}, {"B",13}, {"C",14}
};
// 数字到牌面的映射
string num_to_card(int num){
vector<string> cards = {"3","4","5","6","7","8","9","10","J","Q","K","A","2","B","C"};
return cards[num];
}
int main(){
string hand, played;
// 读取手牌和已出牌
cin >> hand;
cin >> played;
// 统计所有牌的数量(每种牌4张,大小王各1张)
int total_cards[15];
memset(total_cards, 0, sizeof(total_cards));
for(int i=0;i<=14;i++) {
if(i < 13) total_cards[i] = 4;
else total_cards[i] =1;
}
// 统计手牌
string token;
stringstream ss(hand);
while(getline(ss, token, '-')){
if(card_map.find(token) != card_map.end())
total_cards[card_map[token]]--;
}
// 统计已出牌
stringstream ss2(played);
while(getline(ss2, token, '-')){
if(card_map.find(token) != card_map.end())
total_cards[card_map[token]]--;
}
// 构建剩余牌的存在性,仅考虑3到A(0到11)
bool available[12]; // 0到11对应3到A
for(int i=0;i<12;i++) {
available[i] = (total_cards[i] >0);
}
// 寻找最长顺子
int max_len = 0;
int max_end = -1;
for(int start=0; start <= 11-4; start++){ // 最少5张
if(!available[start]) continue;
int current = start;
int len =1;
while(current +1 <12 && available[current+1]){
current++;
len++;
}
if(len >=5){
if(len > max_len || (len == max_len && current > max_end)){
max_len = len;
max_end = current;
}
}
}
if(max_len >=5){
// 输出从 (max_end - max_len +1) 到 max_end
int start = max_end - max_len +1;
string res = "";
for(int i=start;i<=max_end;i++){
res += num_to_card(i);
if(i != max_end) res += "-";
}
cout << res;
}
else{
cout << "NO-CHAIN";
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。