比大小
1 条题解
-
0
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