题目
题面
最近,东东沉迷于打牌。所以他找到 HRZ、ZJM 等人和他一起打牌。由于人数众多,东东稍微修改了亿下游戏规则:
所有扑克牌只按数字来算大小,忽略花色。
每张扑克牌的大小由一个值表示。A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K 分别指代 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13。
每个玩家抽得 5 张扑克牌,组成一手牌!(每种扑克牌的张数是无限的,你不用担心,东东家里有无数副扑克牌)
理所当然地,一手牌是有不同类型,并且有大小之分的。
举个栗子,现在东东的 “一手牌”(记为 α),瑞神的 “一手牌”(记为 β),要么 α > β,要么 α < β,要么 α = β。
那么这两个 “一手牌”,如何进行比较大小呢?首先对于不同类型的一手牌,其值的大小即下面的标号;对于同类型的一手牌,根据组成这手牌的 5 张牌不同,其值不同。下面依次列举了这手牌的形成规则:
1.大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。
2.对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。
3.两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。
4.三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。
5.三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。
6.炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。
7.顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。
8.龙顺:5 张牌分别为 10、J、Q、K、A。
作为一个称职的魔法师,东东得知了全场人手里 5 张牌的情况。他现在要输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。
不料,此时一束宇宙射线扫过,为了躲避宇宙射线,东东慌乱中清空了他脑中的 Cache。请你告诉东东,全场人的排名
输入
输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。
输出
对于每组测试数据,输出 n 行,即这次全场人的排名。
大致题意
看到这堆文字,头都大了。
我将它浓缩一下
题目
有14种牌:A,2,3,4,5,6,7,8,9,10,J,Q,K
有n个玩家,每个玩家5张牌
按照玩家手上牌的大小,大的在前,小的在后,输出玩家姓名
牌大小就是上面的10个规则,规则其实就是分数
1分~大牌(不满足其他规则的牌)·····
事实就是你需要读一下上面8条规则
分析:这周TA讲了做题要有思路,要构成一个框架,大概。
解题分析
首先看到这个题,我们不需要管它的花色,只用看他本身的数值,那就方便多了
第一步:打出代码框架(就是C++框架而已,与题目无关,每次写代码前必备操作
第二步:因为有玩家,玩家手上的牌又属于玩家,牌类型,牌面值总和,
聪明的你想到了什么
struct? yes,you are perfectly right!
ok,让我们先建立一个结构体
struct player{
char s1[20];//玩家姓名
char s2[20];//5张牌
int type,sum;//牌对应的那8种类型,5张牌的面值之和
};
细心的你会发现,比较2个玩家手里的牌,以type优先,type一样的时候
又会根据type里面的规则,然后考虑sum的情况,最后前面所有都相同,
那就考虑玩家姓名了,但是sort本身它要不就是对某个属性值升序
要不就是降序,所以你要自己定义排序规则
你可以bool cmp 在struct外部书写,也可以直接在struct内部重载<
那么根据8个规则,你可以把struct内部书写为:
struct player{
char s1[20],s2[20];//s1姓名,s2牌串
int type,cnt,two[5],three[5],four[5];
//类型,总牌值和,2对,3个,4个
bool operator <(const player &py){//比较方法,用在sort里面
if(type != py.type) return py.type<type; //以类型值优先
else{
switch(type){
case 1://大牌就比较牌值总和
if(cnt!=py.cnt)
return py.cnt<cnt;
case 2:// 对子就比较对子大小,若对子相同,比较其余3张和
if(two[1] != py.two[1])
return py.two[1]<two[1];
else if(cnt != py.cnt)
return py.cnt<cnt;
case 3://2对比较大小,相同就比较其剩下那张
if(two[1]!=py.two[1])
return py.two[1]<two[1];
else if(two[2] != py.two[2])
return py.two[2]<two[2];
else if(cnt!=py.cnt)
return py.cnt<cnt;
case 4: case 5://3个和3带2,情况一样,因为在这里,type是一样的
if(three[1] != py.three[1])//所以你只会比较2种3个或者2种3带2
return py.three[1]<three[1];
else if(cnt != py.cnt)
return py.cnt<cnt;
case 6://炸弹
if(four[1] != py.four[1])
return py.four[1]<four[1];
else if(cnt != py.cnt)
return py.cnt<cnt;
case 7://顺子
if(cnt != py.cnt)
return py.cnt<cnt;
case 8://龙顺就跳出去,两种牌值肯定相同
break;
}//名字字典序,这是个什么玩意,啊啊啊啊,就是字母顺序,开始搞错了
int l=strlen(s1),r=strlen(py.s1),mn;
if(l>r) mn=r;
else mn=l;
for(int i=0;i<mn;i++){
if(s1[i]==py.s1[i])
continue;
else
return s1[i]<py.s1[i];
}
return l<r;
}
}
}p[maxn];
当然啦,结构体写完了,就是思考函数部分了,函数部分就是求出每个玩家
手中牌的具体情况,就是相当于给每个玩家打分
这个可怕的题我WA了很多次,东改改西改改,它就AC了,我很难过,因为我好像把maxn改小了,然后还改了啥来着,它就过了,o(╥﹏╥)o
所以我干了什么?
让测试数据来告诉你吧,自己试疯了都
测试数据(全面
test 1
输入(类型)
8
A 75J210
AB 88JA6
ABC 5599Q
ABCD KKKA4
ABCDE 101010JJ
ABCDEF AAAA5
ABCDEFG 23456
ABCDEFGH 10JAQK
输出:
ABCDEFGH
ABCDEFG
ABCDEF
ABCDE
ABCD
ABC
AB
A
test 2
输入(字典序)
5
AB 45678
ABC 45678
ABD 45678
XYZ 45678
XZY 45678
输出
AB
ABC
ABD
XYZ
XZY
test 3
输入(大牌)
2
AB 749JQ
A 24579
输出
AB
A
test 4
输入(对子)
4
ABC 22567
AB 33245
BCD 22334
BC 22445
输出
BC
BCD
AB
ABC
test 5:
输入:(3个)
6
ABC 777JA
BC 999QK
HEY 66622
HDY 66633
HXY JJJ45
HJY QQQAA
输出:
HJY
HDY
HEY
HXY
BC
ABC
test 6:
输入(炸弹)
4
ABC 55559
BCD 22224
XYY 555510
LYJ JJJJ3
输出
LYJ
XYY
ABC
BCD
test 7:
输入(顺子)
4
ABC 45678
AB 56789
CBD 10JQKA
BBC A2345
输出:
CBD
AB
ABC
BBC
以上的测试数据可以看看你哪个类型的比较或者求值函数有问题,可以对应的去修改。
代码
Codes
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int n,pok[15];
struct player{
char s1[20],s2[20];//s1姓名,s2牌串
int type,cnt,two[5],three[5],four[5];
//类型,总牌值和,2对,3个,4个
bool operator <(const player &py){//比较方法,用在sort里面
if(type != py.type) return py.type<type; //以类型值优先
else{
switch(type){
case 1://大牌就比较牌值总和
if(cnt!=py.cnt)
return py.cnt<cnt;
case 2:// 对子就比较对子大小,若对子相同,比较其余3张和
if(two[1] != py.two[1])
return py.two[1]<two[1];
else if(cnt != py.cnt)
return py.cnt<cnt;
case 3://2对比较大小,相同就比较其剩下那张
if(two[1]!=py.two[1])
return py.two[1]<two[1];
else if(two[2] != py.two[2])
return py.two[2]<two[2];
else if(cnt!=py.cnt)
return py.cnt<cnt;
case 4: case 5://3个和3带2,情况一样,因为在这里,type是一样的
if(three[1] != py.three[1])//所以你只会比较2种3个或者2种3带2
return py.three[1]<three[1];
else if(cnt != py.cnt)
return py.cnt<cnt;
case 6://炸弹
if(four[1] != py.four[1])
return py.four[1]<four[1];
else if(cnt != py.cnt)
return py.cnt<cnt;
case 7://顺子
if(cnt != py.cnt)
return py.cnt<cnt;
case 8://龙顺就跳出去,两种牌值肯定相同
break;
}//名字字典序,这是个什么玩意,啊啊啊啊,就是字母顺序,开始搞错了
int l=strlen(s1),r=strlen(py.s1),mn;
if(l>r) mn=r;
else mn=l;
for(int i=0;i<mn;i++){
if(s1[i]==py.s1[i])
continue;
else
return s1[i]<py.s1[i];
}
return l<r;
}
}
};
player p[maxn];
void Init(){//初始化
for(int i=0;i<=n;i++){
memset(p[i].four,0,sizeof(p[i].four));
memset(p[i].three,0,sizeof(p[i].three));
memset(p[i].two,0,sizeof(p[i].two));
p[i].cnt=0;p[i].type=0;
}
}
void solve(int x){
memset(pok,0,sizeof(pok));
int num=strlen(p[x].s2);
for(int i=0;i<num;i++){//确定牌面值
if(p[x].s2[i]=='J') pok[11]++;
else if(p[x].s2[i]=='Q') pok[12]++;
else if(p[x].s2[i]=='K') pok[13]++;
else if(p[x].s2[i]=='A') pok[1]++;
else if(p[x].s2[i]>='2'&&p[x].s2[i]<='9') pok[p[x].s2[i]-'0']++;
else if(p[x].s2[i]=='1') pok[10]++;
else if(p[x].s2[i]=='0') continue;
}
if(pok[1]&&pok[10]&&pok[11]&&pok[12]&&pok[13]){//龙顺
p[x].type=8;return;
}
for(int i=1;i<=13;i++){ //对5张牌求牌值总和
if(pok[i])
for(int j=1;j<=pok[i];j++)
p[x].cnt+=i;
}
for(int i=13;i>0;i--){
if(pok[i]==4){//炸弹
p[x].type=6;
p[x].four[0]=1;
p[x].four[1]=i;
return;
}
if(pok[i]==3){//3个?为什么不给type值?因为可能3带2
p[x].three[0]=1;
p[x].three[1]=i;
}
if(pok[i]==2){//2对,3带2中的那个
p[x].two[0]++;
if(p[x].two[0]==1)
p[x].two[1]=i;
else{//2对
p[x].two[2]=i;
p[x].type=3;
return;
}
}
}
for(int i=1;i<=9;i++){//求顺子
if(pok[i]&&pok[i+1]&&pok[i+2]&&pok[i+3]&&pok[i+4]){
p[x].type=7;
return;
}
}
if(p[x].two[0]==1&&p[x].three[0]==1){//3带2
p[x].type=5;
return;
}
if(p[x].two[0]==1){//对子
p[x].type=2;
return;
}
if(p[x].three[0]==1){//3个
p[x].type=4;
return;
}
p[x].type=1;//以上情况都不满足,那只有是大牌了
}
int main(){
ios::sync_with_stdio(false);
while(cin>>n){//输入数据,输出结果
Init();
for(int j=1;j<=n;j++){
cin>>p[j].s1>>p[j].s2;
solve(j);
}
sort(p+1,p+n+1);
for(int i=1;i<=n;i++)
cout<<p[i].s1<<endl;
}
return 0;
}