week9 - B - 东东学打牌

题意:

最近,东东沉迷于打牌。所以他找到 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。请你告诉东东,全场人的排名。

思路:

建立一个结构体pai,用于记录拿牌者姓名、牌型,以及各级比较值cmp1、cmp2、cmp3,用于在牌型相同时,进行比较。
在输入每个人的牌之后,先把不同的牌分别用不同数字进行表示,其中,A用1记录,JQK分别用11、12、13记录。
然后给五张牌进行排序,之后即可判断牌型大小,以及各级比较值的大小,然后对所有人的牌进行排序即可得到答案。

代码:

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

struct pai {
	string name;
	int type;
	int cmp1;
	int cmp2;
	int cmp3;
	pai() { cmp1 = cmp2 = cmp3 = 0; }
	bool operator < (const pai& ca) const {
		if (type != ca.type)
			return type < ca.type;
		if (cmp1 != ca.cmp1)
			return cmp1 < ca.cmp1;
		if (cmp2 != ca.cmp2)
			return cmp2 < ca.cmp2;
		if (cmp3 != ca.cmp3)
			return cmp3 < ca.cmp3;
		return name > ca.name;
	}
};

pai p[100010];

int main()
{
	int n; 
	while (scanf("%d", &n) != EOF) {
		//输入并初始化
		for (int i = 0; i < n; i++) {
			cin >> p[i].name;
			string str;
			cin >> str;
			int j = 0, num = 0; 
			int c[60];
			int len = (int)str.size();
			while (j < len) {
				if (str[j] == '1') {
					c[num] = 10;
					num++;
					j = j + 2;
					continue;
				}
				if (str[j] > '1' && str[j] <= '9') {
					c[num] = str[j] - '0';
					num++;
					j++;
					continue;
				}
				if (str[j] == 'A') {
					c[num] = 1;
					num++;
					j++;
					continue;
				}
				if (str[j] == 'J') {
					c[num] = 11;
					num++; 
					j++;
					continue;
				}
				if (str[j] == 'Q') {
					c[num] = 12;
					num++;
					j++;
					continue;
				}
				if (str[j] == 'K') {
					c[num] = 13;
					num++;
					j++;
					continue;
				}
			}
			sort(c, c + 5);
			int sum = c[0] + c[1] + c[2] + c[3] + c[4];
			if (c[0] == 1 && c[1] == 10 && c[2] == 11 && c[3] == 12 && c[4] == 13) {
				//龙顺
				p[i].type = 8;
			}
			else if (c[1] == c[0] + 1 && c[2] == c[0] + 2 && c[3] == c[0] + 3 && c[4] == c[0] + 4) {
				//顺子
				p[i].type = 7;
				p[i].cmp1 = c[4];
			}
			else if (c[0] == c[3] || c[1] == c[4]) {
				//炸弹
				p[i].type = 6;
				p[i].cmp1 = c[1];
				p[i].cmp2 = sum;
			}
			else if ((c[0] == c[2] && c[3] == c[4]) || (c[0] == c[1] && c[2] == c[4])) {
				//三带二
				p[i].type = 5;
				p[i].cmp1 = c[2];//c[2]一定是三张牌的值
				p[i].cmp2 = sum;//三张牌一样,就判断sum
			}
			else if (c[0] == c[2] || c[1] == c[3] || c[2] == c[4]) {
				//三不带
				p[i].type = 4;
				p[i].cmp1 = c[2];//c[2]一定是三张牌的值
				p[i].cmp2 = sum;//三张牌一样,就判断sum
			}
			else if ((c[0] == c[1] && c[2] == c[3]) || (c[0] == c[1] && c[3] == c[4]) || (c[1] == c[2] && c[3] == c[4])) {
				//两个对
				p[i].type = 3;
				p[i].cmp1 = c[3];//c[3]一定是大对的值
				p[i].cmp2 = c[1];//c[1]一定是小对的值
				p[i].cmp3 = sum;//大小对都一样,那就判断sum
			}
			else if (c[0] == c[1] || c[1] == c[2] || c[2] == c[3] || c[3] == c[4]) {
				//一个对
				p[i].type = 2;
				int t;
				for (int k = 0; k < 4; k++) {
					if (c[k] == c[k + 1]) {
						t = k;
					}
				}
				p[i].cmp1 = c[t];
				p[i].cmp2 = sum;
			}
			else {
				p[i].type = 1;
				p[i].cmp1 = sum;
			}
		}
		sort(p, p + n);
		for (int i = n - 1; i >= 0; i--) {
			cout << p[i].name << endl;
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值