-
斗地主
难度:★★★★☆
考察知识点:C语言、排序
题目描述
阿伟是《欢乐斗地主》游戏的爱好者,在跟彬彬一起玩游戏的过程中,他把刚充值的648欢乐豆输了个精光。恼羞成怒的阿伟决定研发一个斗地主辅助器,帮助他赚取欢乐豆。
阿伟决定先实现一个相对简单的功能:输出他的牌里最长且最大的顺子(优先保证最长,其次保证最大)。
我们对“顺子”的定义如下:必须是数组 [3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A]
的连续的一部分,因此我们认为一张单牌也是顺子。
为了简单起见,我们忽略扑克牌的花色和大小王,认为输入只能是 2/3/4/5/6/7/8/9/10/J/Q/K/A
中的任意一个。
2
不能当作顺子的一部分。
使用C或C++语言编写程序。
输入格式
阿伟会把自己的牌(可能是乱序的,且有重复)输入为以空格隔开的一行。
小写的 j/q/k/a
认为是错误输入。
输出格式
如果阿伟输入斗地主中不存在的牌,输出 Illegal cards
。
如果牌里不存在顺子(例如2 2 2 2
),输出 No straight
。
否则,输出所求顺子序列,以空格隔开,不要有多余的内容。
输入输出样例
程序应当能检测各种错误情况。
输入 #1
Just Do It
输出 #1
Illegal cards
输入 #2
abcdefg$# <><> ABAB
输出 #2
Illegal cards
如果用户输入了空行,程序也认为是错误输入。
输入 #3
输出 #3
Illegal cards
但是,如果用户输入中存在多余的空格,程序应能正确解析,而不是报出错误。
输入 #4
4 5 6 7 10 J Q K
输出 #4
10 J Q K
如果存在多个顺子,程序应该优先选择最长的顺子,在同样长度的顺子中,选择最大的顺子。
输入 #5
3 4 5 6 7 8 10 J Q K A
输出 #5
3 4 5 6 7 8
输入 #6
3 4 5 6 7 10 J Q K A
输出 #6
10 J Q K A
为了简化题目,我们规定顺子的长度可以是1。这意味着如果输入的序列中没有顺子,程序应当输出最大的那张牌。
输入 #7
3 5 7 9 J K
输出 #7
K
2永远都不是顺子的一部分,因此如果最大的那张牌是2,则应该输出第二大的那张牌。
输入 #8
3 5 7 9 J A 2
输出 #8
A
如果牌里完全不存在顺子,输出 No straight
。
输入 #9
2 2 2 2
输出 #9
No straight
如果多张同样的牌能组成连对/飞机,你依旧只需要输出顺子。
输入 #10
3 3 4 4 5 5 5 6 6 6
输出 #10
3 4 5 6
输入 #11
3 4 7 8 K K K K A A A A 2
输出 #11
K A
数据范围
-
对于70%的测试数据,我们保证牌的数量小于$$10^4$$,输入数据的总字符数不超过$$10^5$$。
-
对于100%的测试数据,我们保证牌的数量小于$$10^6$$,输入数据的总字符数不超过$$10^7$$。
我们将在 Intel Core i7-1165G7 @ 2.80GHz CPU 上评测你的程序,对于任意一条数据,你的程序需要在1秒内计算出结果。
// 斗地主.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
using namespace std;
static void insertionsort(int arr[], int n)//插入排序
{
for (int i = 1; i < n; i++)
{
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
static int char_to_int(string s)//将字符换成数字,方便排序
{
if (s == "J")
{
return 11;
}
else if (s == "Q")
{
return 12;
}
else if (s == "K")
{
return 13;
}
else if (s == "A")
{
return 14;
}
else if (s == "10")
{
return 10;
}
else {
return stoi(s);
}
}
static string int_to_char(int a)//由数字重新得到字符串
{
if (a == 11) {
return "J";
}
else if (a == 12) {
return "Q";
}
else if (a == 13) {
return "K";
}
else if (a == 14) {
return "A";
}
else if (a == 10)
{
return "10";
}
else {
return to_string(a);
}
}
int main() {
string str;
string arr[100];
string str1[13] = { {"2"},{"3"},{"4"},{"5"},{"6"},{"7"},{"8"},{"9"},{"10"},{"J"},{"Q"},{"K"},{"A"}};//可能出现的所有牌
int index = 0, flag = 1;
while (cin >> str) {//string遇到空格会停止
arr[index++] = str;
for (int i = 0; i < 13; i++)//判断输入的牌是否合法(借用flag来标记)
{
if (str == str1[i])
{
flag = 1;
break;
}
else flag = 0;
}
char ch = getchar();//通过getchar()来判断最后输入回车符结束
if (ch == '\n') break;
if (ch == ' ') continue;//多余的空格忽略
}
if (flag == 0)cout << "Illegal cards";//输入时有非法牌就输出‘illegalcards’
if (flag == 1)//输入的牌合法
{
int n[50]{};
for (int j = 0; j < index; j++)
{
n[j] = char_to_int(arr[j]);
}
insertionsort(n, index);
if (n[index-1] == 2) cout << "No straight";//不存在顺子
else
{
int count[20]{},tmp[20]{}, y = 0, set=0;//count记录顺子长度,tmp记录每个顺子最后一个数,y记录顺子个数,set指示最长的顺子
for (int m = 0; m < index; m++)
{
if (n[m] != 2)
{
if ((n[m + 1] - n[m]) == 1) count[y]++;
else if (n[m] == n[m + 1]) continue;
else
{
tmp[y] = n[m];
y++;
}
}
}
for (int k = 0; k < y; k++)//set找出最长的顺子
{
if (count[k] >= count[k + 1]) set = k;
else set = k + 1;
}
for (int h = count[set]; h >=0; h--)//由下标输出找出的最长顺子
{
cout << int_to_char(tmp[set] - h) << " ";
}
}
}
return 0;
}