模拟:打牌排名问题。c++

题干

扑克游戏规则如下:

所有扑克牌只按数字来算大小,忽略花色。
每张扑克牌的大小由一个值表示。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 张牌不同,其值不同。下面依次列举了这手牌的形成规则:

· 大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。
· 对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。
· 两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。
· 三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。
· 三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。
· 炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。
· 顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。
· 龙顺:5 张牌分别为 10、J、Q、K、A。

现在你得知了全场人手里 5 张牌的情况。要求输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。

输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况

对于每组测试数据,输出 n 行,即这次全场人的排名

sample input:

3
DongDong AAA109
ZJM 678910
Hrz 678910

sample output:

Hrz
ZJM
DongDong

思路:

  • 利用结构体来对每个人拿到的手牌进行记录
  • 观察题目所给的判断条件,首先应该根据牌型进行排位,利用score记录,score越大越在前面
  • 如果牌型中某些标志性牌面相同大小则对比剩余牌的大小,所以定义tot记录手牌的总大小
  • 如果都相同则比较选手的字典序,通过char型数组记录名字只需要一位位进行比较即可
  • 利用三个数组two,three,four来记录手中的牌是否有对子,三张相同和四张相同,数组的第一个元素用01来表示是否具有该种牌型,后面的元素用来记录该牌型的大小。由于需要比较大小,所以在记录牌面的时候要从大到小进行记录
  • 首先记录每一个选手手中的牌,将牌面处理成数字进行存储,记录牌的数量并利用函数给出当前的牌型判断;对于10来说由于读入时10占两位并且只有10的开头是1,所以见到1则忽略掉后一位可以进行10的读入;如果遇到有1 有10 的题目,则需要在读入1的时候判断后面一位是不是0
  • 记录完毕后进行排序,然后依次输出名字
  • 需要注意的是要用多组的数据进行测试,因为判断条件很多,所以容易出现错误,我的WA就是因为一个数组的元素取错 + 少写了一个等号导致 tot 没有正常计算,可以自己多出数据进行测试。
    在这里插入图片描述
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+1;
struct card
{
 char name[11];
 char cards[20];
 int score;//分数
 int tot;//牌面大小
 int two[3];//无对;一对;两对;如果有的话表示是那一对
 int three[2];//没有;有三张相同的牌
 int four[2];//没有,有四张相同的牌 
}poker[N]; 
bool cmp(card a, card b)
{
 if(a.score!=b.score)
 return a.score > b.score;
 else if(a.score==b.score)
 {
  if(a.score==1)//大牌,比牌的大小总和
  {
   if(a.tot!=b.tot)
    return a.tot>b.tot;
  }
  else if(a.score==2)//对子,先比对子大小再比剩下牌的综合
  {
   if(a.two[1]!=b.two[1])
    return a.two[1]>b.two[1];
   else if(a.tot!=b.tot)
    return a.tot>b.tot;
  }
  else if(a.score==3)//两对,先比大队子再小对子再大小
  {
   if(a.two[1]!=b.two[1])
    return a.two[1]>b.two[1];
   else if(a.two[2]!=b.two[2])
    return a.two[2]>b.two[2];
   else if(a.tot !=b.tot)
    return a.tot>b.tot;
  }
  else if(a.score==4)//三个,先比三个大小再比两张综合
  {
   if(a.three[1]!=b.three[1])
    return a.three[1]>b.three[1];
   else if(a.tot!=b.tot)
    return a.tot>b.tot;
  }
  else if(a.score==5)//三代二,先比三个在比两个
  {
   if(a.three[1]!=b.three[1])
    return a.three[1]>b.three[1];
   else if(a.tot!=b.tot)
    return a.tot>b.tot;
  }
  else if(a.score==6)//炸弹先比四个在比一个
  {
   if(a.four[1]!=b.four[1])
    return a.four[1]>b.four[1];
   else if(a.tot!=b.tot)
    return a.tot>b.tot;
  }
  else if(a.score==7)//顺子比顺子大小 
  {
   if(a.tot!=b.tot)
    return a.tot>b.tot;
  }
 }
 //如果都一样,开始比名字的字典序 
 int la=sizeof(a.name);
 int lb=sizeof(b.name);
 int len=min(la,lb);
 for(int i=0;i<len;i++)
 {
  if(a.name[i]!=b.name[i])
  return a.name[i]<b.name[i];
 } 
 if(la<lb) return true;
 return false;
}
void give(int x)
{
 int count=0;
 int temp[15];
 memset(temp,0,sizeof(temp));
 while(count<strlen(poker[x].cards))
 {
  if(poker[x].cards[count]>='2'&&poker[x].cards[count]<='9')
   temp[poker[x].cards[count]-'0']++;
  else
  {
   if(poker[x].cards[count]=='1')
   {
    temp[10]++;
    count++;
   }
   if(poker[x].cards[count]=='A')
    temp[1]++;
   if(poker[x].cards[count]=='J')
    temp[11]++;
   if(poker[x].cards[count]=='Q')
    temp[12]++;
   if(poker[x].cards[count]=='K')
    temp[13]++;   
  }
  count++;
 }
 if(temp[1]&&temp[10]&&temp[11]&&temp[12]&&temp[13])
 {
  poker[x].score=8;
  return;
 }
 for(int i=1;i<=13;i++)
 {
  if(temp[i])
  {
   for(int j=1;j<=temp[i];j++)//就是这里,少个=直接没算tot 
   poker[x].tot+=i;
  }
 }
 for(int i=13;i>=1;i--)//倒着取保证前者大 
 {
  if(temp[i]==4)
  {
   poker[x].four[0]=1;
   poker[x].four[1]=i;
   poker[x].score=6;
   return;
  }
  if(temp[i]==3)
  {
   poker[x].three[0]=1;
   poker[x].three[1]=i;
   //这里还要继续向下判断是哪一个类型 
  }
  if(temp[i]==2)
  {
   poker[x].two[0]++;
   if(poker[x].two[0]==1)
    poker[x].two[1]=i;
   else
   {
    poker[x].two[2]=i;
    poker[x].score=3;
    return;
   }
  }
 } 
  for(int i=1;i<=9;i++)
  {
   if(temp[i]&&temp[i+1]&&temp[i+2]&&temp[i+3]&&temp[i+4])
   {
    poker[x].score=7;
    return;
   }
  }
  if(poker[x].two[0]==1&&poker[x].three[0]==1)
  {
   poker[x].score=5;
   return;
  }
  if(poker[x].two[0]==1)
  {
   poker[x].score=2;
   return;
  }
  if(poker[x].three[0]==1)
  {
   poker[x].score=4;
   return;
  }
  poker[x].score=1;
}
void init(int i)
{
 memset(poker[i].two,0,sizeof(poker[i].two));
 memset(poker[i].three,0,sizeof(poker[i].three));
 memset(poker[i].four,0,sizeof(poker[i].four));
 poker[i].tot=0;
 poker[i].score=0;
}
int main()
{
 int n;
 while(scanf("%d",&n)!=EOF)
 {
  for(int i=1;i<=n;i++)
  {
   init(i);
   scanf("%s %s",&poker[i].name,&poker[i].cards);
   give(i);
  }
  sort(poker+1,poker+n+1,cmp);
  for(int i=1;i<=n;i++)
   printf("%s\n",poker[i].name);
 }
 return 0;
 } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值