(Week 13)综合训练(C++)
创始人
2025-05-31 00:07:43
0

文章目录

    • [Daimayuan]走楼梯2(C++,DP)
        • 输入格式
        • 输出格式
        • 样例输入
        • 样例输出
        • 数据规模
        • 解题思路:
    • [Daimayuan] 任务分配(C++,DP)
        • 输入格式
        • 输出格式
        • 样例输入
        • 样例输出
        • 数据规模
        • 解题思路
    • [Daimayuan]走路(C++,DP)
        • 输入格式
        • 输出格式
        • 输入样例
        • 输出样例
        • 数据规模
        • 解题思路:
    • [Daimayuan]特殊的正方形(C++)
        • 输入格式
        • 输出格式
        • 样例输入
        • 样例输出
        • 数据范围
        • 解题思路:
    • [Daimayuan]订单编号(C++,STL)
        • 输入格式
        • 输出格式
        • 样例输入1
        • 样例输出1
        • 样例输入2
        • 样例输出2
        • 样例输入3
        • 样例输出3
        • 解题思路:
    • [OJ]饿饿 饭饭(C++,二分)
        • 输入格式
        • 输出格式
        • 样例输入1
        • 样例输出1
        • 样例输入2
        • 样例输出2
        • 样例输入3
        • 样例输出3
        • 数据规模
        • 解题思路:
    • [OJ]简单分数统计(C++,字符串)
        • 输入格式
        • 输出格式
        • 样例输入
        • 样例输出
        • 样例解释
        • 解题思路
    • [OJ]Alice的德州扑克(C++,字符串)
        • 输入格式
        • 输出格式
        • 样例输入1
        • 样例输出1
        • 样例输入2
        • 样例输出2
        • 样例输入3
        • 样例输出3
        • 样例输入4
        • 样例输出4
        • 解题思路

[Daimayuan]走楼梯2(C++,DP)

楼梯有 nnn 阶,上楼可以一步上一阶,也可以一步上二阶。

但你不能连续三步都走两阶,计算走到第nnn阶共有多少种不同的走法。

输入格式

一行,一个数字,表示nnn。

输出格式

输出走楼梯的方式总数。

样例输入

6

样例输出

12

数据规模

对于100100100%的数据,保证n≤50n≤50n≤50。

解题思路:

需要遍历每一种情况,很容易想到DP

如果没有限制“不能连续三步都走两阶”,本题就是简单的兔子数列

dp[0] = 1;//简单的初始化条件,台阶数为0,只有一种可能for (int i = 1; i <= max_step; i++)dp[i] = dp[i - 1] + dp[i - 2];

多了限制,自然就少了可能

那么尝试用排除法

需要排除走666、888、101010、141414、.........,显然需要排除的情况太多了

所以我们采用正难则反的思路,正面求解

对于每一步,我们有三种选择(只有三种情况,不难证明):111、222、444

但是需要考虑限制,所以有以下几种情况

(1)当前走了111步,到达此处的方式不受限制

(2)当前走了222步,所以我们只能通过走111步的方式到达此处

(3)当前走了444步,所以我们只能通过走111步的方式到达此处

很简单,于是我们根据这个思路写出代码

int dp[max_step + 1] = { 0 };//存储数据含义:到达当前位置之后的可能数
bool disable[max_step + 1][3] = { false };//限制标记
int step[3] =  { 1,2,4 };dp[0] = 1;//简单的初始化条件,台阶数为0,只有一种可能for (int i = 1; i <= max_step; i++) {for (int j = 0; j < 3; j++) {if (!disable[i - step[j]][j]) {dp[i] += dp[i - step[j]];if (j != 0) disable[i][1] = disable[i][2] = true;//只能通过走1步的方式到达}}
}

结束了?当然没有,这个思路是有一点瑕疵的

假如当前有444级台阶,有几种方法?

很快你就会回答有555种,但是计算机会回答有444种

那么是哪一种可能性被漏掉了呢?

1 1 1 1
2 1 1
1 2 1
1 1 2
2 2

是第三种可能消失了

因为我们被禁止跳222级台阶到达dp[2],但是这不是应该被禁止的吗?

我们要禁止的是跳222级、跳444级连续选择

但是上面的方法会导致跳222级之后跳111级的可能也被去除了,所以我们修改代码,把跳1,2,41, 2, 41,2,4级的情况分开存储

int dp[max_n + 1][3];//存储的数据含义:以方式j到达当前位置之后的可能数
int step[3] = { 1,2,4 };dp[0][0] = dp[0][1] = dp[0][2] = 1;for (int i = 1; i <= max_step; i++) {for (int j = 0; j < 3; j++) {dp[i][0] += dp[i - step[j]][j];if (j == 1) dp[i][j] += dp[i - step[0]][0];else if (j == 2) dp[i][j] += dp[i - step[0]][0];}
}

最后,AC代码如下

#include 
#include 
using namespace std;
const int max_n = 50;
const int bias = 4;//加上偏置量,防止数组越界long long dp[max_n + 1 + bias][3];
int step[3] = { 1,2,4 };int main() {int n;cin >> n;dp[0 + bias][0] = dp[0 + bias][1] = dp[0 + bias][2] = 1;for (int i = 1 + bias; i <= n + bias; i++) {for (int j = 0; j < 3; j++) {dp[i][0] += dp[i - step[j]][j];if (j == 0) {dp[i][1] += dp[i - step[j]][j];dp[i][2] += dp[i - step[j]][j];}}}cout << dp[n + bias][0];return 0;
}

[Daimayuan] 任务分配(C++,DP)

你有nnn个任务,其中第iii个任务,在sis_isi​开始,eie_iei​时刻结束,如果做这个任务,你能获得wiw_iwi​的收益。

但是你在一个时刻只能做一个任务,问选择哪些任务,能让你的收益尽量大。

注意:你在上一个任务结束后马上开始下一个任务是可以的。

输入格式

第一行一个整数nnn。

接下来nnn行,每行三个整数sis_isi​,eie_iei​,wiw_iwi​。

输出格式

一个数,表示答案。

样例输入

3
1 3 100
2 4 199
3 5 100

样例输出

200

数据规模

对于所有数据,保证1≤n≤103,1≤si

解题思路

本题是一道非常规的、同时也是非常好的动态规划题目,具体的“非常规”体现在DP的思路上,接下来说明解题思路

题意抽象来说就是给了起止111~100010001000区间范围内的多条线段,每条线段有自己的权重,选择的线段不能重叠,问如何选使得得到的线段权重最大

很明显,这是一道动态规划问题,那么如何动态规划?

动态规划的关键在于如何从子问题推出更复杂问题的答案

首先我们尝试确定一个子问题的状态:

(1)当前可以得到的最大权重

(2)当前的截止时间

(3)当前考虑的线段数量

先试一下根据(3)展开动态规划,也就是按照常规背包问题的思路

我们会发现我们无法从只考虑前i - 1个物品的情况推导出前i个物品的情况

比如说有如下三条线段

1 2 10
1 3 20
2 4 100

只考虑前两条线段的时候我们可以得到的最大值是20,也就是选择第2条线段

但是我们如果选择第2条线段,我们就不能得到选择13线段的最优解

所以我们换一个角度考虑,有关线段覆盖的问题,终止时间是很重要的

如果到终止时间i之前的最大值是已知的,那么我们就只需要考虑i之后的最大值了

从这里我们可以看出最优子结构的存在

那么尝试一下动态规划,还是这样三条线段

1 2 10
1 3 20
2 4 100

考虑截止时间为3时的最大值,是20

好像我们还是不能从截止时间为3时的最大值推出截止时间为4时的最大值

所以说这道题是一道“非常规”的动态规划问题

我们不是在尝试用截止时间为i - 1时的情况推导出截止时间为i时的情况

而是尝试用截止时间为i时的情况去更新之后所有情况的最大值

for (int i = 1; i < max_se; i++) {dp[i + 1] = max(dp[i + 1], dp[i]);for (int j = 1; j <= n; j++) {if (i == tasks[j].s) {dp[tasks[j].e] = max(dp[tasks[j].e], dp[i] + tasks[j].w);}}
}

我们实现了在到达dp[i]之前,尝试过了所有可能的情况,保证了dp[i]是最优解

然后去尝试所有起始时间是i的任务,更新之后的所有元素

最后,AC代码如下

#include 
using namespace std;
const int max_n = 1e3;
const int max_se = 1e3;
const int max_w = 1e5;struct task { int s, e, w; }tasks[max_n + 1];
int dp[max_se + 1], n;int main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> tasks[i].s >> tasks[i].e >> tasks[i].w;}for (int i = 1; i < max_se; i++) {dp[i + 1] = max(dp[i + 1], dp[i]);for (int j = 1; j <= n; j++) {if (i == tasks[j].s) {dp[tasks[j].e] = max(dp[tasks[j].e], dp[i] + tasks[j].w);}}}cout << dp[max_se] << endl;return 0;
}

[Daimayuan]走路(C++,DP)

有一条很长的数轴,一开始你在000的位置。接下来你要走nnn步,第iii步你可以往右走aia_iai​或者bib_ibi​。

问nnn步之后,000到mmm的每个位置,能不能走到?

输入格式

第一行,两个整数nnn,mmm。

接下来nnn行,每行两个整数aia_iai​,bib_ibi​。

输出格式

一行,一共m+1m+1m+1个数,每个数都是01表示能否走到,数字之间不用空格隔开。

输入样例

3 10
1 2
2 6
3 3

输出样例

00000011001

数据规模

对于所有数据,保证1≤n≤100,1≤m≤105,1≤ai,bi≤10001≤n≤100,1≤m≤105,1≤a_i,b_i≤10001≤n≤100,1≤m≤105,1≤ai​,bi​≤1000。

解题思路:

如果不是像我一样把题看错了的话应该知道这就是一道简单的动态规划问题

一定要看到是“往右走aia_iai​或者bib_ibi​“而不是”往右走aia_iai​或者往左走bib_ibi​“

那么接下来讨论如何实现代码

题意还是有一点模糊的,问的不是你在n步之内能够到达的所有地方,而是你在第n步能够到达的所有地方

显然需要遍历每一种情况,采用动态规划来实现

动态规划最重要的自然是明确每一步需要做什么,也就是状态转移方程:

dp[i][j] = dp[i - 1][j - step[i][0]] || dp[i - 1][j - step[i][1]]

解释一下:

dp[i]代表你当前的是第i

dp[i][j]代表你当前的位置为j

step[i][0]step[i][1]代表你可以向右走几步

也就是说,只要你在第i - 1步时能够到达j - step[i][0]或者j - step[i][1],你就能到达dp[i][j]

最后,AC代码如下

#include 
using namespace std;
const int max_n = 100;
const int max_m = 1e5;
const int max_ab = 1e3;int n, m;
int steps[max_n + 1][2];
bool dp[max_n + 1][max_m + 1];int main() {cin >> n >> m;for (int i = 1; i <= n; i++) {cin >> steps[i][0] >> steps[i][1];}dp[0][0] = true;//初始化for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {if (j - steps[i][0] >= 0)dp[i][j] = (dp[i][j] || dp[i - 1][j - steps[i][0]]);if (j - steps[i][1] >= 0)dp[i][j] = (dp[i][j] || dp[i - 1][j - steps[i][1]]);}}for (int i = 0; i <= m; i++)cout << dp[n][i];return 0;
}

[Daimayuan]特殊的正方形(C++)

输入nnn,输出nnn行nnn列的由+.组成的正方形,其中最外面一圈全是+,第二圈全是.,…,对于第iii圈,如果iii是奇数,那么全是+,否则全是.

输入格式

一行,一个整数nnn。

输出格式

nnn行,为满足题目要求的正方形。注意不要有行末空格。

样例输入

10

样例输出

++++++++++
+........+
+.++++++.+
+.+....+.+
+.+.++.+.+
+.+.++.+.+
+.+....+.+
+.++++++.+
+........+
++++++++++

数据范围

对于100100100%的数据,保证2≤n≤1002≤n≤1002≤n≤100

解题思路:

虽然本题数据范围不大,可以直接实现数组存储,然后输出

但这里仍然采用无存储的方式实现

二维图形输出,自然采用二重循环实现

关键在于如何调整输出.还是+

这里通过两条对角线来实现调整

每次输出前反转两条对角线之间要输出的符号,我们具体模拟一下来说明

初始化输出模式..........

然后我们来到第一行,反转之后的输出模式++++++++++

然后我们来到第二行,反转之后的输出模式+........+

然后我们来到第三行,反转之后的输出模式+.++++++.+

是不是很好理解?但是没有结束,我们需要特殊处理

因为当前每一次循环执行的动作是简单的:反转,然后输出

但是如果这样的话,前半段输出是对的,后半段就会出现错误,如下

++++++++++
+........+
+.++++++.+
+.+....+.+
+.+.++.+.+
+.+....+.+
+.++++++.+
+........+
++++++++++
..........

所以我们稍微调整一下:

(1)前半段:反转,然后输出

(2)后半段:输出,然后反转

最后,AC代码如下

#include 
using namespace std;
const int max_n = 100;char pattern[max_n];	//每行的输出模式
bool save[max_n];		//处理模式的调整//反转
inline void reverse(char& c) {if (c == '.') c = '+';else c = '.';
}int main() {int n;bool change = false;cin >> n;for (int i = 0; i < n; i++) pattern[i] = '.';//初始化for (int i = 0; i < n; i++) {if (save[i]) {//后半段:先输出,后反转cout << pattern << endl;for (int j = 0; j < n; j++) {if (i == j || i + j == n - 1) {//判断对角线save[i] = save[n - i] = true;change = !change;reverse(pattern[j]);j++;while (change) {reverse(pattern[j]);if (i == j || i + j == n - 1) {//判断对角线change = !change;}else {j++;}}}}}else {//前半段:先反转,后输出int j;for (j = 0; j < n; j++) {//特殊判定:如果对角线交于一点if (i == j && i + j == n - 1) {reverse(pattern[i]);}else {//常规if (i == j || i + j == n - 1) {//判断对角线save[i] = save[n - 1 - i] = true;change = !change;reverse(pattern[j]);j++;while (change) {reverse(pattern[j]);if (i == j || i + j == n - 1) {//判断对角线change = !change;}else {j++;}}}}}cout << pattern << endl;if (i == n / 2) {//特殊判定:如果对角线交于一点reverse(pattern[i]);}}}return 0;
}

[Daimayuan]订单编号(C++,STL)

小缘开了一家公司,生意很好,每天都会收到很多订单,自动交易系统会自动给这些订单生成没有重复的订单编号。但是有一天,系统出现了未知的错误,导致当天的订单编号可能有重复的,这可把小缘急坏了。你可以帮助小缘按照规则给这些订单重新编号吗?

按照时间先后顺序给出 NNN 个正整数作为原订单编号,你需要按照规则依次赋予这些订单新的编号,对于任意一个订单,要找到大于等于其原订单编号且未被使用过的(没有被之前的订单作为新的订单编号)的最小整数,作为它的新订单编号。

例如: 原订单编号依次为111 222 333 111,则新订单编号应该为111 222 333 444 (前333个订单的原订单编号都没有使用过,所以用其原订单编号即可,对于第四个订单,原订单编号为111,而111, 222, 333都已经被使用过,所以新订单编号为444)。

输入格式

第一行输入一个整数 NNN (1≤N≤5×1051≤N≤5×10^51≤N≤5×105)。

第二行输入 NNN 个数 aia_iai​ (1≤ai≤1091≤a_i≤10^91≤ai​≤109) 作为原订单编号。

输出格式

输出一行,包含 NNN 个整数为新的订单编号。

样例输入1

6
2 3 4 1 1 1

样例输出1

2 3 4 1 5 6

样例输入2

3
1000000000 1000000000 1000000000

样例输出2

1000000000 1000000001 1000000002

样例输入3

6
4 5 1 2 1 1

样例输出3

4 5 1 2 3 6

解题思路:

本题考察对STL的掌握

采用set+pair维护未使用序号的区间来解决本题

主要是利用setlower_bound方法:传入一个val,返回集合中大于等于val的最小值;如果是pair数据类型,默认先比较first再比较second

代码如下

#include 
#include 
using namespace std;
const int max_a = 1e9;
const int max_n = 5e5;int n, a;
set>s;int main() {s.insert(pair(2 * max_a, 1));cin >> n;int out_temp = 0;for (int i = 0; i < n; i++) {cin >> a;auto ret = s.lower_bound({ a,0 });if (ret->second < a) {cout << a << ' ';s.insert(pair(a - 1, ret->second));if (ret->first != a)s.insert(pair(ret->first, a + 1));s.erase(ret);}else {cout << ret->second << ' ';if (ret->first != ret->second)s.insert(pair(ret->first, ret->second + 1));s.erase(ret);}}cout << out_temp;return 0;
}

[OJ]饿饿 饭饭(C++,二分)

有nnn个同学正在排队打饭,第iii个同学排在从前往后第iii个位置。但是这天食堂内只有一个食堂阿姨,为了使同学们都能尽快的吃上饭,每一个同学在打完一份饭之后就会排在队伍的末尾先吃着打到的饭,我们知道第iii个同学的饭量为aia_iai​,也就是说第iii个同学要吃aia_iai​份饭才能吃饱,当一位同学吃饱后,他就会立刻离开食堂,不会排在队伍的末尾。食堂阿姨想知道,在打完k份饭之后,队伍的样子是怎样的,但是食堂阿姨数学不太好,想让你帮忙想想办法。

输入格式

第一行给出两个整数nnn,kkk。

第二行给出nnn个整数a1a_1a1​,a2a_2a2​,…ana_nan​。

输出格式

如果食堂阿姨打饭数少于kkk,请输出-1

否则按照队伍顺序输出每一个同学的编号。

样例输入1

3 3
1 2 1

样例输出1

2

样例输入2

4 10
3 3 2 1

样例输出2

-1

样例输入3

7 10
1 3 3 1 2 3 1

样例输出3

6 2 3

数据规模

数据保证1≤n≤105,0≤k≤1014,1≤ai≤1091≤n≤105, 0≤k≤1014, 1≤a_i≤10^91≤n≤105,0≤k≤1014,1≤ai​≤109。

解题思路:

先采用二分搜索找出需要多少轮才能分完所有的饭,如果找不到输出-1

反之先进行ret - 1轮,然后模拟最后一轮,最后输出即可

代码如下

#include 
#include 
using namespace std;
const long long max_n = 1e5;
const long long max_k = 1e14;
const long long max_a = 1e9;long long n, k;
long long students[max_n + 1];
queueans;bool judge(long long loop) {long long sum = 0;for (int i = 1; i <= n; i++) {sum += min(students[i], loop);}return sum <= k;
}long long bin_search() {long long l = 0, r = k + 2;while (l + 1 != r) {long long m = (l + r) / 2;if (judge(m)) l = m;else r = m;}return l;
}int main() {cin >> n >> k;for (int i = 1; i <= n; i++) cin >> students[i];long long ret = bin_search();for (int i = 1; i <= n; i++) {k -= min(ret, students[i]);students[i] -= min(ret, students[i]);}if (ret == k + 1 && k > 0) {cout << -1 << endl;return 0;}for (int i = 1; i <= n; i++) {if (students[i] > 0) {if (k > 0) {students[i]--;k--;if (students[i] > 0) ans.push(i);}else {cout << i << ' ';}}}while (!ans.empty()) {cout << ans.front() << ' ';ans.pop();}return 0;
}

[OJ]简单分数统计(C++,字符串)

NNN 个好朋友在codeforcescodeforcescodeforces上参加一场包含 MMM 个题目的比赛, 比赛期间codeforcescodeforcescodeforces网站一共有 kkk 次提交。

已知每个题目的分数,

但是由于他们只能查到在比赛期间codeforcescodeforcescodeforces总共的提交记录(其他用户提交的其他题目记录也包含在内, 即存在不属于该场比赛的题目),

所以想请你编写一个程序算出他们每个人的分数。

输入格式

第一行三个整数 NNN, MMM, KKK 分别表示好朋友的个数, 题目的个数, 和提交的总次数(其中0

接下来 NNN 行 第 iii 行输入为第 iii 个人的ididid,

接下来 MMM 行 第 jjj 行输入为第 jjj 个题目的名称和分数,

接下来 KKK 行 第 kkk 行输入为第 kkk 次提交的提交者iii, 题目名称和结果(“WA” 或 “AC”, 如果"AC"代表通过这个题目, 提交者获得对应分数)。

注: 题目名称和id均为仅包含英文字母和数字的字符串, 题目分数为小于等于 1e61e61e6 的正整数. 每一行的多个输入之间用空格隔开。

所有输入的字符串长度 lengthlengthlength 满足 0

所有用户id和题目名称不存在重名, 用户AC了某个题之后之后不会再重复提交该题, 好朋友们只会提交属于比赛的题目。

输出格式

输出 NNN 行, 第 iii 行输出第 iii 个人的名字和对应分数 (名字和分数用空格隔开)。

样例输入

2 2 4
GabrielPessoa
beza
metebronca 100
geometry 200
beza metebronca AC
ffern numbertheory AC
GabrielPessoa geometry WA
beza geometry AC

样例输出

GabrielPessoa 0
beza 300

样例解释

bezabezabeza 过了 metebroncametebroncametebronca和geometrygeometrygeometry 拿到 300300300 分。

GabrielPessosGabrielPessosGabrielPessos 没有过题, 所以是 000 分。

还有一些其他选手提交的其他题目忽略不计。

解题思路

一道考察字符串的题目

对于提交者,用map转换id为数组索引号

对于题目,用map转换名字为分数

然后判断是否AC累加求和即可

AC代码如下

#include 
#include 
using namespace std;
const int max_n = 200;
const int max_m = 200;
const int max_k = 200;int n, m, k, sc;
string name, ques, res;
mapid2idx;
mapques2score;
long long ans[max_n + 1];
string names[max_n + 1];int main() {cin >> n >> m >> k;for (int i = 1; i <= n; i++) {cin >> names[i];id2idx.insert(pair(names[i], i));}for (int j = 1; j <= m; j++) {cin >> ques >> sc;ques2score.insert(pair(ques, sc));}map::iterator ret;for (int i = 0; i < k; i++) {cin >> name >> ques >> res;ret = id2idx.find(name);if (ret != id2idx.end() && res == "AC") {ans[ret->second] += ques2score[ques];}}for (int i = 1; i <= n; i++) {cout << names[i] << ' ' << ans[i] << endl;}return 0;
}

[OJ]Alice的德州扑克(C++,字符串)

德州扑克是目前世界上最流行的扑克游戏,全世界有众多相关的比赛,例如是 WSOP,WPT,EPT等,也让这款游戏的玩法变得层出不穷,丰富多变。 不要被简单的游戏规则而误导,复杂多变的比赛状况,让这款游戏在高水平的竞技中会变得非常复杂,这也让人们为德州扑克给出了这样一句评价 ”用一刻就能学会,但要用一生才能掌握” 。

现在我们并不在乎游戏规则是什么,因为 Alice 是一个德州扑克高手,他对于德州扑克的规则烂熟于心,不过他每次都记不得牌型的大小关系,他知道你是一个编程高手,所以他想让你帮他写一个程序:输入五张牌的大小和花色,输出这五张牌能组成的最大牌型.你能帮帮他吗?

为了降低你的编程难度,我们规定:

  1. 输入的牌都是来源于同一副扑克牌
  2. 输入的牌的点数都是非递减的
  3. 所有花色没有大小之分

下面给出各牌型,(从大到小)

  1. 皇家同花顺(ROYAL FLUSH):五张顺连的牌(点数连续单调递增),且最大的一张牌是A(Ace),并且五张牌的花色相同
  2. 同花顺(STRAIGHT FLUSH):五张顺连的牌(点数连续单调递增),不规定最大的一张牌是A(Ace),并且五张牌的花色相同
  3. 四条(FOUR OF A KIND):至少四张牌的点数相同
  4. 葫芦(FULL HOUSE):至少三张牌的点数相同,并且除此之外还有两张牌的点数相同
  5. 同花(FLUSH):五张牌的花色都相同
  6. 顺子(STRAIGHT):五张顺连的牌(点数连续单调递增),不要求五张牌的花色相同
  7. 特别注意:由于 Alice 是个谨慎的人,所以比 三条(THREE OF A KIND) (包括三条) 小的牌型 Alice 不在乎他们的大小关系,你只需要告诉 Alice 弃牌就行

输入格式

输入两行,每行五个数字,第一行的第 iii 个字符表示第 iii 张扑克的点数,

第二行的第 iii 个数字表示第 iii 张扑克花色。(保证输入的牌的点数是非递减的,且所有输入均合法)

点数和对应输入的数字:

  • 2−102−102−10 对应 2−102 - 102−10
  • J(Jack)J(Jack)J(Jack) 对应 111111
  • Q(Queen)Q(Queen)Q(Queen) 对应 121212
  • K(King)K(King)K(King) 对应 131313
  • A(Ace)A(Ace)A(Ace) 对应 141414

花色和对应输入的数字:

  • 黑桃$ (Spades)$ 对应 111
  • 方片 (Diamonds)(Diamonds)(Diamonds) 对应 222
  • 红桃 (Hearts)(Hearts)(Hearts) 对应 333
  • 梅花 (Clubs)(Clubs)(Clubs) 对应 444

输出格式

输出这五张牌能组成的最大牌型。

  • 如果最大是皇家同花顺输出 “ROYAL FLUSH”
  • 如果最大是同花顺输出 “STRAIGHT FLUSH”
  • 如果最大是四条输出 “FOUR OF A KIND”
  • 如果最大是葫芦输出 “FULL HOUSE”
  • 如果最大是同花输出 “FLUSH”
  • 如果最大是顺子输出 “STRAIGHT”
  • 如果最大的牌型小于等于三条输出"FOLD",劝 Alice 弃牌
  • 输出不包括引号

样例输入1

10 11 12 13 14
1 1 1 1 1

样例输出1

ROYAL FLUSH

样例输入2

10 11 12 13 14
1 2 1 3 4

样例输出2

STRAIGHT

样例输入3

6 6 6 7 7
1 2 3 1 3

样例输出3

FULL HOUSE

样例输入4

3 3 6 6 9
1 2 1 2 1

样例输出4

FOLD

解题思路

这里将要说明的代码的适用范围要比题目所给出的更广

因为我题读错了QAQ

所以只是想要解决原题问题的可以划过去了

改动了以下几点:

(1)输入两行,以换行符结尾

(2)第一行输入若干个扑克牌点数,分别是222~101010和JJJ,QQQ,KKK,AAA

首先这是一道模拟问题

我们可以注意到,不同combocombocombo之间是有包含关系的,而且所有combocombocombo由五种条件组合而成:

(1)顺子:五张连续

(2)同花:五张同花

(3)222张、333张、444张点数相同

所以我们的判定自然也有顺序,这样就可以简化问题

输入点数之后我们就可以寻找(1)和(3)了

之后判断是否有顺子、葫芦和四条

然后输入点数,寻找(2)

当且仅当顺子和同花已经找到的情况下,我们继续寻找最大的两种combocombocombo

最后输出最大的combocombocombo即可

//Alice的德州扑克
#include 
#include 
#include 
using namespace std;
const int flower_num = 4;
const int max_card_num = 14;mapstr2point;
bool cards[flower_num + 1][max_card_num + 1];	//cards
int flower_sum[flower_num + 1];					//card flower sum
int card_sum[max_card_num + 1];					//card point sum
bool same_flower_nlt5[flower_num + 1];			//same flower no less than 5
bool combo[6];									//combo
string ans[6] = {								//combo2sting"STRAIGHT", "FLUSH", "FULL HOUSE","FOUR OF A KIND", "STRAIGHT FLUSH", "ROYAL FLUSH"
};//card2point
void init() {str2point.insert(pair("2", 2));str2point.insert(pair("3", 3));str2point.insert(pair("4", 4));str2point.insert(pair("5", 5));str2point.insert(pair("6", 6));str2point.insert(pair("7", 7));str2point.insert(pair("8", 8));str2point.insert(pair("9", 9));str2point.insert(pair("10", 10));str2point.insert(pair("J", 11));str2point.insert(pair("Q", 12));str2point.insert(pair("K", 13));str2point.insert(pair("A", 14));
}int main() {//initializeinit();//input card pointstring str;char c = '\0';while (c != '\n' && c != '\r') {cin >> str;c = getchar();card_sum[str2point[str]]++;}//STRAIGH, FLUSH and FOUR OF A KIND//initializebool same_point[3] = { false };int last_point = 0, conseq = 0, i = 2;//search for combofor (; i <= max_card_num; i++) {//for STRAIGHTif (card_sum[i]) {if (last_point + 1 == i) {conseq++;if (conseq >= 5) {combo[0] = true;//STRAIGHTbreak;}}else conseq = 1;last_point = i;}//for FULL HOUSE and FOUR OF A KINDif (card_sum[i] >= 4 && !same_point[2])same_point[2] = true;else if (card_sum[i] >= 3 && !same_point[1])same_point[1] = true;else if (card_sum[i] >= 2 && !same_point[0])same_point[0] = true;}//FOUR OF A KINDif (same_point[2]) combo[3] = true;//FULL HOUSEif (int(same_point[2]) + int(same_point[1]) + int(same_point[0]) >= 2) combo[2] = true;//initializeint flower;//input card flowerfor (int i = 2; i <= max_card_num; i++) {while (card_sum[i]) {cin >> flower;cards[flower][i] = true;card_sum[i]--;flower_sum[flower]++;}}//search for FLUSHfor (int i = 1; i <= flower_num; i++) {if (flower_sum[i] >= 5) {same_flower_nlt5[i] = true;combo[1] = true;//FLUSH}}//search for STRAIGHT FLUSH and ROYAL FLUSHif (combo[0] && combo[1]) {//have found STRAIGHT and FLUSHfor (int i = 1; i <= flower_num; i++) {if (same_flower_nlt5[i]) {//initializeint j = 2;while (!cards[i][j]) j++;last_point = j; conseq = 1;//for STRAIGHT FLUSH and ROYAL FLUSHfor (; j <= max_card_num; j++) {if (cards[i][j]) {if (last_point + 1 == j) {last_point = j;conseq++;if (conseq >= 5) {combo[4] = true;if (last_point == 14) {combo[5] = true;}}}else {last_point = j;conseq = 1;}}}}}}//output phasefor (int i = 5; i >= 0; i--) {if (combo[i]) {cout << ans[i] << endl;return 0;}}cout << "FOLD" << endl;return 0;
}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...