1 条题解

  • 0
    @ 2025-5-12 17:50:56

    题目描述

    在德州扑克中,每位玩家会获得两张底牌,同时桌面上会有五张公共牌。玩家需要从这七张牌中选出五张组成最佳牌型。本题要求我们根据给定的七张牌(前五张为公共牌,后两张为底牌),找出对手可能组成的最强五张牌牌型。如果存在多个花色可以组成相同的最强牌型,则用 '*' 表示花色。输出时,牌需要按点数降序排列(A 始终视为最大),若点数相同则按花色顺序排列('*' 排最后),并附上牌型的全大写名称。

    解题思路

    1. 理解牌型优先级

    首先,我们需要明确德州扑克中各种牌型的优先级(从高到低):

    1. 皇家同花顺 (ROYAL FLUSH)
      A、K、Q、J、10,同花色。
    2. 同花顺 (STRAIGHT FLUSH)
      五张连续点数且同花色的牌(A 可以作为最大或最小,但不能同时使用)。
    3. 四条 (FOUR OF A KIND)
      四张同点数的牌,剩余一张为任意牌。
    4. 葫芦 (FULL HOUSE)
      三张同点数 + 一对。
    5. 同花 (FLUSH)
      五张同花色的牌,点数不连续。
    6. 顺子 (STRAIGHT)
      五张连续点数的牌,花色不限。
    7. 三条 (THREE OF A KIND)
      三张同点数的牌,剩余两张为任意牌。

    2. 对手的可能牌型

    对手的牌型由五张公共牌中的任意五张组成(因为对手的底牌未知)。我们需要遍历所有可能的五张牌组合,找出其中最强的牌型。

    3. 牌型判断逻辑

    对于任意五张牌,我们需要依次判断其是否符合以下牌型(从高到低检查):

    1. 皇家同花顺:检查是否为 A、K、Q、J、10 且同花色。
    2. 同花顺:检查是否为连续点数且同花色。
    3. 四条:检查是否有四张同点数牌。
    4. 葫芦:检查是否三张同点数 + 一对。
    5. 同花:检查是否五张同花色。
    6. 顺子:检查是否五张连续点数。
    7. 三条:检查是否三张同点数。

    4. 处理花色平局

    如果存在多个花色可以组成相同的最强牌型(例如,同花顺可以用不同花色组成),则用 '*' 表示花色。

    5. 输出格式

    • 牌按点数降序排列(A 最大,2 最小)。
    • 若点数相同,按花色顺序排列(c < d < h < s < '*')。
    • 牌型名称用全大写字母表示。

    代码实现思路

    1. 输入处理:读取输入数据,解析每张牌的点数和花色。
    2. 生成所有可能的五张牌组合:从七张牌中选取五张,计算所有组合。
    3. 牌型判断:对每个五张牌组合,判断其牌型。
    4. 选择最强牌型:在所有可能的牌型中,选择最强的。
    5. 处理平局:如果有多个花色可选,用 '*' 表示。
    6. 输出结果:按规则排序并输出。

    示例分析

    输入:

    9c As 3h 8d 2s Jh Ah
    

    输出:

    As 5* 4* 3h 2s STRAIGHT
    

    解释:

    • 公共牌:9c As 3h 8d 2s
    • 底牌:Jh Ah
    • 可能的五张牌组合中,最强的牌型是 顺子 (STRAIGHT),由 As 3h 2s Jh Ah 组成(A 作为最大点数,但这里需要进一步验证逻辑是否正确)。

    总结

    本题的关键在于:

    1. 正确判断牌型:从高到低依次检查每种牌型。
    2. 处理花色平局:用 '*' 表示多个可选花色。
    3. 排序输出:按点数和花色顺序排列。

    通过遍历所有可能的五张牌组合,并比较它们的牌型,我们可以找到对手可能的最强牌型。

    代码实现

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define pii pair<int,int>
    using namespace std;
    
    const int RANK_OFFSET = 2;
    const int SUIT_OFFSET = 1;
    
    inline int decode(char c) {
        if(c == 'c') return 1;
        if(c == 'd') return 2;
        if(c == 'h') return 3;
        if(c == 's') return 4;
        if('2' <= c && c <= '9') return c - '0';
        switch(c) {
            case 'T': return 10;
            case 'J': return 11;
            case 'Q': return 12;
            case 'K': return 13;
            case 'A': return 14;
            default: return 0;
        }
    }
    
    struct poker {
        pii a[5];
        int v1, v2;
        bool operator == (const poker& that) const {
            return v1 == that.v1 && v2 == that.v2;
        }
        bool operator < (const poker& that) const {
            return v1 == that.v1 ? v2 < that.v2 : v1 < that.v1;
        }
    };
    
    pii hand[7];
    bool vis[15][5]; // [rank][suit], rank 2-14, suit 1-4
    
    // Comparison function for sorting cards
    bool card_compare(const pii& x, const pii& y) {
        return x.first != y.first ? x.first > y.first : x.second < y.second;
    }
    
    inline void evaluate_hand(poker& cur) {
        pii a[5];
        memcpy(a, cur.a, sizeof(a));
        sort(a, a+5);
        
        bool flush = true;
        for(int i = 1; i < 5; i++) 
            if(a[i].second != a[i-1].second) 
                flush = false;
        
        bool straight = false;
        if(a[0].first + 1 == a[1].first && 
            a[1].first + 1 == a[2].first && 
            a[2].first + 1 == a[3].first && 
            a[3].first + 1 == a[4].first) {
            straight = true;
        }
        else if(a[4].first == 14 && 
            a[0].first == 2 && 
            a[1].first == 3 && 
            a[2].first == 4 && 
            a[3].first == 5) {
            straight = true;
        }
        
        int counts[15] = {0};
        for(int i = 0; i < 5; i++) counts[a[i].first]++;
        
        int four = 0, three = 0, pairs = 0;
        for(int i = 2; i <= 14; i++) {
            if(counts[i] == 4) four = i;
            else if(counts[i] == 3) three = i;
            else if(counts[i] == 2) pairs++;
        }
        
        // Royal Flush
        if(flush && straight && a[4].first == 14 && a[0].first == 10) {
            cur.v1 = 7;
            return;
        }
        // Straight Flush
        if(flush && straight) {
            cur.v1 = 6;
            cur.v2 = (a[4].first == 14 && a[3].first == 5) ? 5 : a[4].first;
            return;
        }
        // Four of a Kind
        if(four) {
            cur.v1 = 5;
            int kicker = 0;
            for(int i = 0; i < 5; i++) 
                if(a[i].first != four) 
                    kicker = a[i].first;
            cur.v2 = four * 20 + kicker;
            return;
        }
        // Full House
        if(three && pairs >= 1) {
            cur.v1 = 4;
            int pair_val = 0;
            for(int i = 2; i <= 14; i++)
                if(counts[i] == 2) pair_val = i;
            cur.v2 = three * 20 + pair_val;
            return;
        }
        // Flush
        if(flush) {
            cur.v1 = 3;
            cur.v2 = 0;
            for(int i = 4; i >= 0; i--) 
                cur.v2 = cur.v2 * 20 + a[i].first;
            return;
        }
        // Straight
        if(straight) {
            cur.v1 = 2;
            cur.v2 = (a[4].first == 14 && a[3].first == 5) ? 5 : a[4].first;
            return;
        }
        // Three of a Kind
        if(three) {
            cur.v1 = 1;
            int kickers[2] = {0};
            int idx = 0;
            for(int i = 4; i >= 0; i--)
                if(a[i].first != three && idx < 2)
                    kickers[idx++] = a[i].first;
            cur.v2 = three * 400 + kickers[0] * 20 + kickers[1];
            return;
        }
        // Default case (high card)
        cur.v1 = 0;
    }
    
    void generate_combinations(int start, int pos, int remaining, poker& cur, poker& best_hand) {
        if(remaining == 0) {
            evaluate_hand(cur);
            if(best_hand.v1 < cur.v1 || (best_hand.v1 == cur.v1 && best_hand.v2 < cur.v2)) {
                best_hand = cur;
            }
            return;
        }
        
        for(int i = start; i <= 7 - remaining; i++) {
            cur.a[pos] = hand[i];
            generate_combinations(i+1, pos+1, remaining-1, cur, best_hand);
        }
    }
    
    void find_best_hand(poker& best_hand) {
        poker current;
        generate_combinations(0, 0, 5, current, best_hand);
    }
    
    void output_hand(const poker& p) {
        pii a[5];
        memcpy(a, p.a, sizeof(a));
        sort(a, a+5, card_compare);
        
        for(int i = 0; i < 5; i++) {
            printf("%c%c ", "0023456789TJQKA"[a[i].first], "*cdhs"[a[i].second]);
        }
        
        static const char* hand_names[] = {
            "", "THREE OF A KIND", "STRAIGHT", "FLUSH", 
            "FULL HOUSE", "FOUR OF A KIND", "STRAIGHT FLUSH", "ROYAL FLUSH"
        };
        puts(hand_names[p.v1]);
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        while(T--) {
            memset(vis, 0, sizeof(vis));
            
            for(int i = 0; i < 7; i++) {
                char s[3];
                scanf("%2s", s);
                hand[i] = make_pair(decode(s[0]), decode(s[1]));
                vis[hand[i].first][hand[i].second] = true;
            }
            
            poker best_hand = {{}, -1, -1};
            find_best_hand(best_hand);
            
            // Check for wildcard possibilities (opponent's possible hands)
            poker opponent_best = best_hand;
            for(int r = 2; r <= 14; r++) {
                for(int s = 1; s <= 4; s++) {
                    if(vis[r][s]) continue;
                    
                    hand[5] = make_pair(r, s);
                    for(int rr = r; rr <= 14; rr++) {
                        for(int ss = 1; ss <= 4; ss++) {
                            if(rr == r && ss <= s) continue;
                                if(vis[rr][ss]) continue;
                                
                                hand[6] = make_pair(rr, ss);
                                poker current_best = {{}, -1, -1};
                                find_best_hand(current_best);
                                
                                if(opponent_best < current_best) {
                                    opponent_best = current_best;
                                }
                        }
                    }
                }
            }
            
            output_hand(opponent_best);
        }
        return 0;
    }
    • 1

    信息

    ID
    1025
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    4
    已通过
    1
    上传者