Week9 - 程序设计思维与实践 - 东东学打牌(模拟)

题面

最近,东东沉迷于打牌。所以他找到 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 行,即这次全场人的排名。

样例输入

3

DongDong AAA109

ZJM 678910

Hrz 678910

样例输出

DongDong

ZJM

Hrz

思路

第六周模拟题 的延伸,判断手牌的类别的思路基本不变,把 5 张牌放入 map ,根据 map 的大小以及 key-value 的值即可确定类别;对于牌的大小对比,根据题意重载 < ,然后调用 sort 进行排序最后输出结果即可。
因为直接从上份代码的基础上改了改,这里的重载写得有点麻烦了…我直接把对应的map以数组的形式拷贝到了结构体里,然后两个结构体的map再进行比较,其实大可不必。在结构体内声明几个变量,分别表示牌值的加和、出现次数为4,3,2,1的牌大小,也可实现相同功能。

代码实现

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;

int n,b[5];
char s1[20],s2[20];
map<char,int> mp;

struct player{
	string name;
	int val;
	int element[5];
	int c[10];
	int d[15];
	bool operator<(const player &s)const{		
		if(val==s.val){
			int tot1=0,tot2=0;
			for(int i=0;i<5;i++){
				tot1+=element[i];
				tot2+=s.element[i];
			}
			if(val==8)
				return  name<s.name;
			else if(val==7){
				if(element[4]!=s.element[4])
					return element[4]>s.element[4];
				else
					return name<s.name; 
			}
			else if(val==6){
				int bomb1=c[4]==0?c[5]:c[4];
				int bomb2=s.c[4]==0?s.c[5]:s.c[4];
				if(bomb1!=bomb2){
					return bomb1>bomb2;
				}
				else{
					if(tot1!=tot2)
						return tot1>tot2;
					else
						return name<s.name;					
				}		
			}
			else if(val==5){
				if(c[3]==s.c[3]){
					if(c[2]==s.c[2])
						return name<s.name;
					else
						return c[2]>s.c[2];
				}
				else
					return c[3]>s.c[3];
			}
			else if(val==4){
				if(c[3]==s.c[3]){
					if(tot1!=tot2)
						return tot1>tot2;
					else
						return name<s.name;
				}
				else
					return c[3]>s.c[3];
			}
			else if(val==3){
				vector<int> two1,two2;
				for(int i=1;i<=13;i++){
					if(d[i]==2)
						two1.push_back(i);
					if(s.d[i]==2)
						two2.push_back(i);
				}			
				sort(two1.begin(),two1.end());
				sort(two2.begin(),two2.end());				
				if(two1[1]==two2[1]){
					if(two1[0]==two2[0]){
						if(tot1!=tot2)
							return tot1>tot2;
						else
							return name<s.name;						
					}
					else
						return two1[0]>two2[0];
				}
				else
					return two1[1]>two2[1];
			}
			else if(val==2){
				if(c[2]==s.c[2]){
					if(tot1!=tot2)
						return tot1>tot2;
					else
						return name<s.name;					
				}
				else
					return c[2]>s.c[2];
			}
			else{
				if(tot1!=tot2)
					return tot1>tot2;
				else
					return name<s.name;					
			}
		}
		else
			return val>s.val;
	}
}a[100010];

int Value(string s,int cnt){
	int idx=0;
	for(int i=0;i<s.size();i++){
		if(s[i]=='1'){
			if(i+1>=s.size()){
				b[idx++]=1;
			}
			else{
				if(s[i+1]=='0'){
					b[idx++]=10;
					i++;
				}
				else{
					b[idx++]=1;
				}
			}
		}
		else
			b[idx++]=mp[s[i]];
	}
	sort(b,b+5);
	for(int i=0;i<5;i++){
		a[cnt].element[i]=b[i];
	} 
	//龙顺子 
	if(b[0]==1&&b[1]==10&&
		b[2]==11&&b[3]==12&&b[4]==13)
		return 8;	
	int x=b[0];
	bool flag=true;
	map<int,int> p;
	for(int i=0;i<5;i++){
		p[b[i]]++;
		if(i>0){
			if(b[i]!=++x)
				flag=false;
		}
	}
	//顺子 
	if(flag)
		return 7;
	for(int j=0;j<10;j++){
		a[cnt].c[j]=a[cnt].d[j]=0;
	}	
	for(int j=10;j<15;j++){
		a[cnt].d[j]=0;
	}
	for(map<int,int>::iterator t=p.begin();t!=p.end();t++){
		a[cnt].c[t->second]=t->first;
		a[cnt].d[t->first]=t->second;
	}
	int size=p.size();
	map<int,int>::iterator it=p.begin();
	//4张牌相等 
	if(size==1)
		return 6;
	else if(size==2){
		//4张牌相等
		if(it->second==4||it->second==1)
			return 6;
		//3张牌相等,另外2张也相等	
		return 5;		
	}
	else if(size==3){
		while(it!=p.end()){
			//3张牌相等
			if(it->second==3)
				return 4;
			it++; 
		}
		//有2个不同的对子
		return 3;		
	}
	else if(size==4){
	//2张牌相等
		return 2;		
	}
	else
	//大牌 
		return 1;
}

int main()
{
	mp['A']=1;mp['2']=2;mp['3']=3;mp['4']=4;mp['5']=5;
	mp['6']=6;mp['7']=7;mp['8']=8;mp['9']=9;
	mp['J']=11;mp['Q']=12;mp['K']=13;
	while(~scanf("%d",&n)){
		for(int cnt=0;cnt<n;cnt++){
			scanf("%s",s1);
			scanf("%s",s2);	
			string element=s2;
			a[cnt].val=Value(s2,cnt);	
			a[cnt].name=s1;		
		}	
		sort(a,a+n);
		for(int i=0;i<n;i++){
			printf("%s\n",a[i].name.c_str());		
		}
	}
	return 0;
}

记一次教训!!!!!
在这里插入图片描述
在重载 < < < 时,
在这里插入图片描述
有一个地方忘记写 return ,但在本地编译时被优化了,提交OJ一直提示段错误,一开始以为是 map 的 [] 没有对边界的判断,或者其他数组越界问题,也没有想到没写 return 这个问题(主要是重载那里写得有点乱),把所有数组和map在每组数据结束后都清空了一遍,还把 map 都改成数组了,每种情况也都出了几组数据,结果都正确,提交后还是段错误,心态有点崩,后来单步进 sort 函数调试,才发现这个低级问题…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值