top1编程
← 返回题目
题解

比大小

1 条题解

  • 0
    @ 2026-8-6 0:09:19

    P4693 比大小(【基础】)

    解题思路

    要赢小A,我们的 n 张牌点数之和必须比小A的大。怎样选最有利?当然是选剩余牌堆里点数最大的 n 张——如果点数最大的 n 张都赢不了小A,那换成更小的牌就更不可能赢了。下面分五步实现。

    **第一步,建整副牌。**先把整副 52 张牌按花色 S(黑桃)、D(方块)、C(梅花)、H(红心)和点数 A、2……K 的顺序存进 deck 数组。每张牌记录三个信息:点数 point、花色 suit、点数字符 rank。点数字符要转成点数,写一个 getPoint 函数:'A' 是 1,'2'~'9' 是 2~9,'T' 是 10,'J' 是 11,'Q' 是 12,'K' 是 13。

    **第二步,标记小A的牌。**读入小A 的 n 张牌,在 taken 数组里把对应牌做上标记,同时用 opponentSum 累加小A的点数和。

    **第三步,收集剩余牌。**把没被小A抽走的牌按原牌组顺序放进 remaining 数组,个数记作 remCount。

    **第四步,排序取前 n 张。**把 remaining 按点数从大到小排序,取前 n 张。这 n 张就是剩余牌堆里点数最大的 n 张。

    **第五步,判断并输出。**如果前 n 张的点数之和 mySum 大于小A的 opponentSum,就逐行输出这 n 张牌(每行两个字符:花色+点数);否则输出 -1。

    为什么取最大的 n 张就对?因为每张牌都要用,要让总和最大,就该优先选点数大的;如果最大 n 张都赢不了,任何其他选法的总和只会更小,更赢不了。

    边界情况:T 最多 200 组数据,每组都要重新建标记数组,别忘了清零;牌面顺序按 sort 的结果来,和评测数据保持一致。

    参考代码

    // P4693 比大小:从剩余牌堆选n张点数之和最大的牌,能赢小A就输出,否则输出-1
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    struct Card {
        int point;   // 点数
        char suit;   // 花色
        char rank;   // 点数字符
    };
    
    // 把点数字符转成点数,如 'A'->1, '2'->2, 'T'->10, 'K'->13
    int getPoint(char c) {
        if (c == 'A') return 1;
        if (c >= '2' && c <= '9') return c - '0';
        if (c == 'T') return 10;
        if (c == 'J') return 11;
        if (c == 'Q') return 12;
        return 13;   // K
    }
    
    // 只按点数从大到小
    bool cmp(const Card &a, const Card &b) {
        return a.point > b.point;
    }
    
    int main() {
        // 整副52张牌:花色按 S(黑桃) D(方块) C(梅花) H(红心),点数 A 2 3 ... 9 T J Q K
        Card deck[52];
        char suits[4] = {'S', 'D', 'C', 'H'};
        char ranks[13] = {'A', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K'};
        int deckCount = 0;
        for (int i = 0; i < 4; i++)
            for (int j = 0; j < 13; j++) {
                deck[deckCount].suit = suits[i];
                deck[deckCount].rank = ranks[j];
                deck[deckCount].point = getPoint(ranks[j]);
                deckCount++;
            }
    
        int T;
        cin >> T;
        while (T--) {
            int n;
            cin >> n;
            int taken[52] = {0};        // 标记小A抽走的牌
            int opponentSum = 0;        // 小A的点数和
            for (int i = 0; i < n; i++) {
                char suitChar, rankChar;
                cin >> suitChar >> rankChar;
                for (int j = 0; j < 52; j++)
                    if (deck[j].suit == suitChar && deck[j].rank == rankChar) { taken[j] = 1; break; }
                opponentSum += getPoint(rankChar);
            }
            // 剩余牌按原牌组顺序放入remaining
            Card remaining[52];
            int remCount = 0;
            for (int j = 0; j < 52; j++)
                if (!taken[j]) remaining[remCount++] = deck[j];
            sort(remaining, remaining + remCount, cmp);
            int mySum = 0;
            for (int i = 0; i < n; i++) mySum += remaining[i].point;
            if (mySum <= opponentSum) {
                cout << -1 << "\n";
            } else {
                for (int i = 0; i < n; i++) cout << remaining[i].suit << remaining[i].rank << "\n";
            }
        }
        return 0;
    }
    

    复杂度分析

    每组数据最多对 52 张牌排序,sort 的时间复杂度 O(52 log 52),相当于常数。T 最多 200 组,总时间非常小。空间 O(52)。

    • 1