题解

题面描述

斗地主起源于湖北十堰房县,据说是一位叫吴修全的年轻人根据当地流行的扑克玩法“跑得快”改编的,如今已风靡整个中国,并流行于互联网上。

牌型:单顺,又称顺子,最少 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 张牌)。

思路

  1. 牌面表示:
  2. 将牌面转化为数字表示,便于比较和排序。按照给定的顺序,3 到 A 分别对应 0 到 11,2 对应 12,小王和大王分别对应 13 和 14。由于顺子不能包含 2、小王和大王,因此有效牌面范围为 0 到 11。
  3. 计算剩余牌:
  4. 总牌数为每种牌4张(不包括大小王),需要从总牌中减去手中持有的牌和已出过的牌,得到剩余对手可能持有的牌。
  5. 统计牌面:
  6. 统计剩余牌中每种牌的数量。如果某种牌的剩余数量大于0,说明对手可能持有该牌。
  7. 寻找最长顺子:
  8. 遍历从 3 到 A 的所有可能的连续序列。
  9. 对于每一个可能的起始点,尝试尽可能延长顺子的长度,确保每张牌至少存在一张。
  10. 记录所有可能的顺子,选择最长的那个。如果有多个长度相同的顺子,选择牌面最大的。
  11. 输出结果:
  12. 根据找到的最长顺子输出对应的牌面,如果无法找到符合条件的顺子,输出 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";
    }
}


灵芸小骏
8.5k 声望692 粉丝

移动开发者。