当前位置: 首页 > news >正文

欧拉计划 Project Euler54(扑克手牌)题解

欧拉计划 Project Euler 54 题解

  • 题干
      • 🥇 胜负判定规则
      • 🎴 示例对局
      • 📄 数据说明
      • ✅ 问题目标
  • 思路
  • code

题干

在扑克游戏中,玩家的手牌由五张牌组成,其等级由低到高分别为:

  • 单牌:牌面最大的一张牌。
  • 对子:两张牌面一样的牌。
  • 两对:两个不同的对子。
  • 三条:三张牌面一样的牌。
  • 顺子:五张牌的牌面是连续的。
  • 同花:五张牌是同一花色。
  • 葫芦:三条带一个对子。
  • 四条:四张牌面一样的牌。
  • 同花顺:五张牌的牌面是连续的且为同一花色。
  • 皇家同花顺:同一花色的 10、J、Q、K、A。

牌面从小到大的顺序为:2、3、4、5、6、7、8、9、10、J、Q、K、A。

🥇 胜负判定规则

  • 若两名玩家的手牌等级不同,等级高者胜。
  • 若手牌等级相同,则比较组成该等级的牌中最大的牌
  • 若继续相同,比较剩余牌的大小,直到区分胜负。

🎴 示例对局

手牌编号玩家 1玩家 2说明胜者
1红桃5 草花5 黑桃6 黑桃7 方片K草花2 黑桃3 黑桃8 方片8 方片10一对8 > 一对5玩家2
2方片5 草花8 黑桃9 黑桃J 草花A草花2 草花5 方片7 黑桃8 红桃QA > Q玩家1
3方片2 草花9 黑桃A 红桃A 草花A方片3 方片6 方片7 方片10 方片Q同花 > 三条玩家2
4方片4 黑桃6 红桃9 红桃Q 草花Q方片3 方片6 红桃7 方片Q 黑桃Q一对Q,最大单牌 9 > 7玩家1
5红桃2 方片2 草花4 方片4 黑桃4草花3 方片3 黑桃3 黑桃9 方片9葫芦(三条4 > 三条3)玩家1

📄 数据说明

在文件 poker.txt 中,共包含 1,000 局扑克游戏:

  • 每行代表一局;
  • 每行有 10 张牌,前 5 张是 玩家 1 的手牌,后 5 张是 玩家 2 的手牌;
  • 所有手牌都是有效的且不重复;
  • 每局都有明确的赢家。

✅ 问题目标

统计:在这 1000 局游戏中,玩家 1 获胜的局数。



思路

这个题是个大模拟题,注意细节不要漏掉A5顺子,A可以当1使用,具体实现看代码,给了大量注释

  • 解析每行牌,分配给两个玩家;
  • 分别计算双方手牌的牌型与比较值;
  • 判断谁胜出并统计玩家1的胜场次数。

code

// ans = 376
#include <bits/stdc++.h>using namespace std;using ll = long long;// 扑克牌面值的映射关系
// poker.txt 中的10是用T表示的
map<char, int> value_map = {{'2', 2}, {'3', 3}, {'4', 4}, {'5', 5}, {'6', 6},{'7', 7}, {'8', 8}, {'9', 9}, {'T', 10}, {'J', 11},{'Q', 12}, {'K', 13}, {'A', 14}
};// 表示一张牌
struct Card {int value; // 牌的点数,例如 2-14(A 是 14)char suit; // 牌的花色,例如 'H'、'D'、'C'、'S' 红桃 方块 梅花 黑桃
};// 比较两张牌的大小 从大到小排序
bool cmp(const Card &a, const Card &b) {return a.value > b.value;
}// 将字符串形式的牌转换为结构体形式并排序
vector<Card> parse_hand(const vector<string> &str_hand) {vector<Card> hand;for (const string &s : str_hand) {hand.push_back({value_map[s[0]], s[1]});}sort(hand.begin(), hand.end(), cmp);return hand;
}// 评估手牌的等级和关键的点数 用于后续的比较
pair<int, vector<int>> evaluate_hand(const vector<Card> &hand) {vector<int> values;map<int, int> counts;set<char> suits;// 统计每张牌的点数和花色for (const auto &card : hand) {values.push_back(card.value);counts[card.value]++;suits.insert(card.suit);}sort(values.begin(), values.end(), greater<int>());// 根据点数统计频次并排序// 优先比较数量多的 再比较点数大的vector<pair<int, int>> freq;for (auto &[val, cnt] : counts) {freq.push_back({cnt, val});}sort(freq.begin(), freq.end(), [](auto &a, auto &b){return a.first == b.first ? a.second > b.second : a.first > b.first;});bool flush = suits.size() == 1; // 同花// 顺子bool straight = false;// 检查一般的顺子if (values[0] - values[4] == 4 && set<int>(values.begin(), values.end()).size() == 5) {straight = true;} else {// 检查 A-5 顺子 (A, 5, 4, 3, 2)vector<int> ace_low_straight_values = {14, 5, 4, 3, 2};vector<int> current_values_sorted = values;sort(current_values_sorted.begin(), current_values_sorted.end());vector<int> values_for_ace_low = {2, 3, 4, 5, 14};sort(values_for_ace_low.begin(), values_for_ace_low.end());if (current_values_sorted == values_for_ace_low) {straight = true;// 为了让 A-5 顺子在比较时被正确处理,将其最高牌视为 5values = {5, 4, 3, 2, 1}; // 使用 1 来表示 A 作为最低牌的情况}}// 依次判断每个等级 从高到低// 皇家同花顺if (flush && straight && values[0] == 14) return {10, {}};// 同花顺if (flush && straight) return {9, {values[0]}};// 四条if (freq[0].first == 4) return {8, {freq[0].second, freq[1].second}};// 葫芦if (freq[0].first == 3 && freq[1].first == 2) return {7, {freq[0].second, freq[1].second}};// 同花if (flush) return {6, values};// 顺子if (straight) {if (values[0] == 5 && values[4] == 1) return {5, {5}}; // A-5 straight represented by 5return {5, {values[0]}};}// 三条if (freq[0].first == 3) {vector<int> result = {freq[0].second};for(const auto& val : values) {if (val != freq[0].second) {result.push_back(val);}}return {4, result};}// 两对if (freq[0].first == 2 && freq[1].first == 2) {vector<int> result = {freq[0].second, freq[1].second};for(const auto& val : values) {if (val != freq[0].second && val != freq[1].second) {result.push_back(val);break;}}return {3, result};}// 对子if (freq[0].first == 2) {vector<int> result = {freq[0].second};int kickers_count = 0;for(const auto& val : values) {if (val != freq[0].second && kickers_count < 3) {result.push_back(val);kickers_count++;}}return {2, result};}return {1, values};
}bool player1_wins(const vector<string> &cards) {vector<string> p1(cards.begin(), cards.begin() + 5);vector<string> p2(cards.begin() + 5, cards.end());auto hand1 = evaluate_hand(parse_hand(p1));auto hand2 = evaluate_hand(parse_hand(p2));return hand1 > hand2;
}void solve() {ifstream file("poker.txt");string line;int ans = 0;while (getline(file, line)) {istringstream iss(line);vector<string> cards(10);for (int i = 0; i < 10; ++i) {iss >> cards[i];}if (player1_wins(cards)) ans++;}cout << ans << "\n";}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int tt = 1; // cin >> tt;while (tt--) {solve();}return 0;
}

相关文章:

  • MySQL运算符
  • stack和queue的学习
  • 【实证分析】ESG发展对企业新质生产力影响的研究—来自中国A股上市企业的经验
  • ROS第十二梯:ros-noetic和Anaconda联合使用
  • Python常用的第三方模块之【pymysql库】操作数据库
  • HarmonyOS 5.0应用开发——MVVM模式的应用
  • CF2103F Maximize Nor
  • AI 人工智能模型:从理论到实践的深度解析⚡YQW · Studio ⚡【Deepseek】【Chat GPT】
  • 深度学习中的黑暗角落:梯度消失与梯度爆炸问题解析
  • springboot+vue 支付宝支付(沙箱方式,测试环境使用)
  • VUE Element-ui Message 消息提示组件自定义封装
  • 如何在编译命令中添加灰度标识
  • cnas认证注意事项,cnas认证审核有效期?cnas认证难吗?
  • 思科路由器密码绕过+重置
  • uniapp小程序使用echarts
  • 湖南大学-操作系统实验四
  • python——模块、包、操作文件
  • 如何选择 Flask 和 Spring Boot
  • 【数据结构入门训练DAY-21】信息学奥赛一本通T1334-围圈报数
  • 深入解析C++ STL Stack:后进先出的数据结构
  • 天津航空一航班盘旋14圈才降落,客服:因天气影响
  • 思政课也精彩,“少年修齐讲堂”开讲《我的中国“芯”》
  • 《水饺皇后》领跑五一档票房,《哪吒2》上座率仍居第一
  • 当农民跨进流动的世界|劳动者的书信①
  • 万达电影去年净利润亏损约9.4亿元,计划未来三年内新增25块IMAX银幕
  • 秦洪看盘|资金切换主线,重构市场风格