小红最近迷上了纸牌。纸牌有黑桃(Spade)、红桃(Heart)、方块(Diamond)、梅花(Club)四种花色,并且每张纸牌上面写了一个正整数。小红拿到了许多牌,准备玩以下游戏:
为了简化,本题仅计算同花顺这一牌型:即取出的5张牌构成同花顺,则可以获得1分。其他牌型均不得分。
所谓同花顺,即五张牌花色相同,且排序后满足
小红想知道,经过若干次操作后,自己最多可以得到多少分?
请注意,同一个牌型可能出现多次!
第一行输入一个正整数,代表牌堆中牌的种类(如果两张牌的花色或数值不同,则认为种类不同)。
接下来的行,每行输入两个正整数:
和
和一个字符
,分别代表每种牌的大小、数量以及花色。
∈{'S','H','D','C'},代表扑克牌的四种花色:黑桃(Spade)、红桃(Heart)、方块(Diamond)、梅花(Club)。
保证每个种类的牌在输入中只出现了一次。
一个整数,代表小红可以最多获得的分数。
6 1 1 S 2 2 S 3 2 S 4 2 S 5 2 S 1 10 H
1
可以取到一个同花顺:。虽然有10个红桃1,但无法和其他牌凑成同花顺
6 1 1 H 2 2 H 3 2 H 4 2 H 5 2 H 6 10 H
2
可以取两次:和
。
#include <iostream> #include <map> #include <string> #include <algorithm> using namespace std; // 统一处理单个花色的逻辑 void processSuit(map<int, int>& suit, long long& score) { for (auto it = suit.begin(); it != suit.end(); ) { int x = it->first; bool isStraight = true; // 检查x+1到x+4是否存在(避免使用operator[],防止自动插入) for (int i = 1; i <= 4; ++i) { if (suit.find(x + i) == suit.end()) {//如果find不到,会返回.end() isStraight = false; break; } } if (isStraight) {//存在同花顺 // 计算最小数量(确保所有数量非负) int minCnt = it->second; if (minCnt < 0) minCnt = 0; // 防御性检查 for (int i = 1; i <= 4; ++i) { int cnt = suit.at(x + i); // 使用at(),不存在会抛异常(便于调试) if (cnt < 0) cnt = 0; minCnt = min(minCnt, cnt); } // 只有正数量才加分 if (minCnt > 0) { score += minCnt; // 减去数量,确保不小于0 it->second = max(0, it->second - minCnt); for (int i = 1; i <= 4; ++i) { suit[x + i] = max(0, suit.at(x + i) - minCnt); } } } // 更新迭代器(删除数量为0的牌) if (it->second == 0) { it = suit.erase(it); } else { ++it; } } } int main() { int n;//牌堆中牌的种类(如果两张牌的花色或数值不同,则认为种类不同)。 cin >> n; //思考:怎么存储 //4个map<int,int>,前面int是“大小”,后面int是数量 map<int, int> S; map<int, int> H; map<int, int> D; map<int, int> C; for (int i = 0; i < n; i++) { //每行输入两个正整数:a_i和cnt_i和一个字符c_i,分别代表每种牌的大小、数量以及花色。 int a_i = 0, cnt_i = 0; char c_i;//c_i∈{'S','H','D','C'} cin >> a_i >> cnt_i >> c_i; if (c_i == 'S') { S[a_i] = cnt_i; } else if (c_i == 'H') { H[a_i] = cnt_i; } else if (c_i == 'D') { D[a_i] = cnt_i; } else { C[a_i] = cnt_i; } } //查询时就遍历某个花色,看存不存在同花顺 long long score = 0;//防止溢出 processSuit(S, score); processSuit(H, score); processSuit(D, score); processSuit(C, score); cout << score; return 0; }
def main():
n = int(input())
poker = {
"S": {},
"H": {},
"D": {},
"C": {},
}
for i in range(n):
x, num, color = input().split(" ")
poker[color][int(x)] = int(num)
total = 0
for color in "SHDC":
ans = 0
grade = 0
nums = poker[color]
# 以数字 k 开头的顺子
keys = list(nums.keys())
keys = sorted(keys)
for k in keys:
cur = [nums[k]]
# 是否都存在
for i in range(1, 5):
if (k + i) in nums and nums[k + i] > 0:
cur.append(nums[k + i])
else:
break
# 都存在就算分
if len(cur) == 5:
grade = min(cur)
# 拿走牌
for i in range(5):
if (k + i) in nums:
nums[k + i] -= grade
ans += grade
total += ans
print(total)
#include <bits/stdc++.h>
#define ll long long
using namespace std;
struct Card {
ll val;
ll count;
char style;
Card(ll val, ll count, char style) : val(val), count(count), style(style) {}
};
void checkStraightFlush(vector<Card>& cards, ll& ans) {
ll size = cards.size();
if (size < 5) return;
// 按牌值升序排序
sort(cards.begin(), cards.end(), [](const Card & x1, const Card & x2) {
return x1.val < x2.val;
});
ll i=0;
while (i <= size - 5) {
while(cards[i].count<=0) i++;
ll begVal = cards[i].val;
bool isStraight = true;
ll minCount=cards[i].count;//取最小牌数量(代表可以消掉的最少组)
for (ll j = 1; j < 5; ++j) {
if (cards[i + j].val != begVal + j||cards[i+j].count<=0) {
isStraight = false;
i=i+j;//从中断处重新找
break;
}
minCount=min(minCount,cards[i+j].count);
}
if (isStraight) {
ans += minCount;
for (int j = 0; j < 5; ++j) cards[i + j].count-=minCount;
}
}
}
int main() {
ll n;
cin >> n;
unordered_map<char, vector<Card>> hash;
while (n--) {
ll val, count;
char style;
cin >> val >> count >> style;
hash[style].emplace_back(val, count, style);
}
vector<char> styles = {'S', 'H', 'D', 'C'};
ll ans = 0;
for (char s : styles) {
auto& cards = hash[s];
checkStraightFlush(cards, ans);
}
cout << ans << endl;
return 0;
}