yzoj 2377 颂芬梭哈 题解

题意

Alice 和 Mukyu 最近偶然得到了一本写有一种叫做梭哈的扑克游戏的规则的说明书(名为《C████████nd》,中间部分被涂掉了),据其所述,梭哈是一种使用黑桃、红心、梅花、方片的 A 到 K 共 52 张牌(没有大小王)来进行的扑克牌游戏。

不幸的是,规则说明中有关整个游戏的进行方式的部分被撕掉了,Alice 和 Mukyu 从残存的部分只得知了“手牌上限是 5 张”这一消息,所以他们决定每次直接给两人各发 5 张牌,判定谁的手牌比较大,说明书中关于手牌大小判定的信息如下:

所有五张牌的组合,按以下秩序,由大至小排行分为不同牌型:

1、同花顺(Straight Flush):同一花色,顺序的牌。 例: Q♦ J♦ 10♦ 9♦ 8♦;

2、四条(Four of a Kind):有四张同一点数的牌。 例: 10♣ 10♦ 10♥ 10♠ 9♥;

3、满堂红(Full House):三张同一点数的牌,加一对其他点数的牌。 例: 8♣ 8♦ 8♠ K♥ K♠;

4、同花(Flush):五张同一花色的牌。 例: A♠ K♠ 10♠ 9♠ 8♠;

5、顺子(Straight):五张顺连的牌。 例: K♦ Q♥ J♠ 10♦ 9♦;

6、三条(Three of a kind):有三张同一点数的牌。 例: J♣ J♥ J♠ K♦ 9♠;

7、两对(Two Pairs):两张相同点数的牌,加另外两张相同点数的牌。 例: A♣ A♦ 8♥ 8♠ Q♠;

8、一对(One Pair):两张相同点数的牌。 例: 9♥ 9♠ A♣ J♠ 8♥;

9、无对(Zilch):不能排成以上组合的牌,以点数决定大小。例: A♦ Q♦ J♠ 9♣ 8♣。

若牌型一样则利用点数和花色决定胜负。(点数优先)

点数的顺序(从大至小)为:A>K>Q>J>10>9>8>7>6>5>4>3>2。(注:当 5 张手牌是 5 4 3 2 A 的时候,A 可以看作最小的牌,此时的牌型仍然为顺子,是顺子里面最小的一个)。

花色的顺序(大至小)为:黑桃(♠)>红心(♥)>梅花(♣)>方块(♦)。

举例说明:
1、Q♦ J♦ 10♦ 9♦ 8♦ > 8♣ 8♥ 8♠ K♥ K♠ (前者牌型为同花顺,比后者大);

2、9♣ 9♦ 9♠ Q♥ Q♠ > 8♣ 8♦ 8♠ K♥ K♠ (两者牌型均为满堂红,比较牌型中三张同一点数的牌 9 比 8 大);

3、A♣ A♦ 8♥ 8♠ Q♠ > A♠ A♥ 7♥ 7♠ K♠ (两者牌型均为两对,且最大的对子相同,此时比较次大的对子,8 比 7 大);

4、A♠ Q♠ J♥ 9♥ 8♥ > A♦ Q♦ J♠ 9♣ 8♣ (两者牌型均为无对,所有数码均相同,此时比较最大牌的花色,A♠ > A♦)。

5、4♠ 4♥ A♦ Q♦ 5♦ > 4♣ 4♦ A♠ Q♠ 5♠ (两者牌型均为一对,所有数码均相同,此时对 4 为牌型里最大的部分,因此比较 4♠ > 4♣)


尽管 Alice 和 Mukyu 都可以轻易的判断出结果,他们还是想见识一下现代科技的力量。

输入格式

第一行包含一个正整数 N,表示有 N 组测试数据。

每组测试数据包含 10 行,前 5 行每行用两个整数描述一张 Alice 手上的牌,第一个数表示牌的数码(1 表示 A,13 表示 K),第二个数表示牌的花色(1 表示黑桃,2 表示红心, 3 表示梅花,4 表示方块)。

后 5 行每行用两个整数描述 Mukyu 手上的牌,格式同上。

输出格式

对于每组测试数据,在单独的一行内输出 Alice 或 Mukyu,表示谁能赢。

样例输入

1
1 3
5 3
4 3
3 3
2 3
6 1
10 4
7 1
8 1
9 2

样例输出

Alice

样例解释

Alice 的手牌构成同花顺,而 Mukyu 的手牌仅构成普通顺子。

数据范围

对于 10%的数据,保证输入的全部牌型都是无对。
对于另外 30%的数据,保证输入的全部牌型都是顺子、同花或同花顺。
对于 100%的数据,保证 N ≤ 100000。
C++选手如果使用 cin 读入数据很可能因此超时,推荐使用 scanf/printf。

解析

一道大模拟,按照题意模拟即可,细节还是蛮多的,讲下大致思路,

1.先按照点数降序排序后我们可以按照5张牌中花色的种类和点数的种类以及出现最多的相同点数的次数分类,先找出牌型和其中最大的一张牌的点数,我们可以根据上面的参数分辨大部分牌型。

我们用mcol表示花色种类,mdata表示点数种类,mcom表示出现最多的相同点数的次数。

四条: mcol4&&mdata2&&mcom==4

满堂红:mcol>=3&&mdata2&&mcom3

三条:mcol>=3&&mdata3&&mcom3

两对:mcol>=2&&mdata3&&mcom2

一对:mcol>=2&&mdata4&&mcom2

顺子:mcol>=1&&mdata5&&mcom0(其中可能出现无对

同花顺,同花:mcol1&&mdata5&&mcom==0

其中只需细分顺子,同花顺,同花,剩下的就是无对。

2.按照题意特殊处理 $ A $即可。 $ A $ 可以和 $ 2 3 4 5 $ 组成顺子,也可以和 $ 10 J Q K $ 组成顺子,并且在四条,满堂红,三条,两对,一对,同花的时候要把 $ 1->A $ 此处记得特判。

3.值得注意的是这道题的判断比较稍微麻烦一些,因为它需要先比较牌型的点数而不是最大一张牌的点数,所以较为麻烦,下面详细解释一下。

顺子,同花顺:对于顺子我们可以直接比较上面求到的最大的一张牌的点数和花色,因为我们知道顺子是连续的,所以说如果最大的一张牌的点数相同他们所以数码就一定相同。

四条,满堂红,三条:直接判断最中间的点数,排完序后,三/四张相同的一定在中间,因为只有52张牌,所以不肯能出现点数相同的情况,所以直接比较点数即可。

同花:倒序枚举每张牌的点数,如果码数相同比较花色,因为52张牌所以花色必不可能相同。

两对:找出其中的两个对子,先比较较大的对子的点数,再比较较小的对子的点数,如果还是相同再比较最后一张单牌的点数,最后比较较大对子的点数,同理只有52张牌,所以如果码数相同那么花色必然不可能相同。

单对:同理先找出对子,比较对子点数,再比较单牌点数,最后比较对子花色

无对:倒序枚举判断每一张单牌点数,最后判断最大一张的花色。

代码

#include<bits/stdc++.h>
using namespace std;
struct node{
	int data;//点数 
	int col;//花色 
}b[10],c[20];
struct Node{
	int data;//点数 
	int col;//花色 
	int num;//种类 
};
int n,ans;
bool cmp(node a,node b){
	return a.data<b.data;
}
node find(node a[]){
	int maxcol=0;//最大花色 
	int maxdata=0;//最大点数 
	node p;
	for(int i=5;i>=1;--i){//逆过来! 
		if(a[i].data>=maxdata){
			maxdata=a[i].data;
			maxcol=max(a[i].col,maxcol);
		}
	}
	p.data=maxdata;
	p.col=maxcol;
	return p;
}
Node cheak(node a[]){
	int mdata=0;//点数种类
	int mcol=0;//花色种类 
	int mcom=0;//某个点数出现最多的次数  
	int book[20];
	memset(book,0,sizeof(book));
	for(int i=1;i<=5;++i){//找花色种类 
		if(!book[a[i].col]){
			book[a[i].col]=1;
			mcol++;
		}
	}
	memset(book,0,sizeof(book));
	for(int i=1;i<=5;++i){//找点数种类 及 次数 
		if(!book[a[i].data]){
			book[a[i].data]++;
			mdata++;
		}else{
			book[a[i].data]++;
			mcom=max(mcom,book[a[i].data]);
		}
	}
	if(mcol==4&&mdata==2&&mcom==4){//四条,把1换成A无影响 
		for(int i=1;i<=5;++i){
			if(a[i].data==1) a[i].data=14;
		}
		sort(a+1,a+6,cmp); 
		node tmp=find(a);
		Node ans;
		ans.col=tmp.col;
		ans.data=tmp.data;
		ans.num=2;
		return ans;
	}
	else if(mcol>=3&&mdata==2&&mcom==3){//满堂红,把1换成A无影响 
		for(int i=1;i<=5;++i){
			if(a[i].data==1) a[i].data=14;
		} 
		sort(a+1,a+6,cmp); 
		node tmp=find(a);
		Node ans;
		ans.col=tmp.col;
		ans.data=tmp.data;
		ans.num=3;
		return ans;
	}
	else if(mcol>=3&&mdata==3&&mcom==3){//三条,把1换成A无影响  
		for(int i=1;i<=5;++i){
			if(a[i].data==1) a[i].data=14;
		} 
		sort(a+1,a+6,cmp); 
		node tmp=find(a);
		Node ans;
		ans.col=tmp.col;
		ans.data=tmp.data;
		ans.num=6;
		return ans;
	}
	else if(mcol>=2&&mdata==3&&mcom==2){//两对,把1换成A无影响 
		for(int i=1;i<=5;++i){
			if(a[i].data==1) a[i].data=14;
		}
		sort(a+1,a+6,cmp);
		node tmp=find(a);
		Node ans;
		ans.col=tmp.col;
		ans.data=tmp.data;
		ans.num=7;
		return ans;
	}
	else if(mcol>=2&&mdata==4&&mcom==2){//一对,把1换成A无影响  
		for(int i=1;i<=5;++i){
			if(a[i].data==1) a[i].data=14;
		}
		sort(a+1,a+6,cmp);
		node tmp=find(a);
		Node ans;
		ans.col=tmp.col;
		ans.data=tmp.data;
		ans.num=8;
		return ans;
	}
	else if(mcol>=1&&mdata==5&&mcom==0){//同花顺,同花,顺子 
		if(mcol>1){//顺子 
			bool flag=1;
			for(int i=2;i<5;++i){//判断2-5是不是连着的 
				if(a[i+1].data!=a[i].data+1) flag=0;
			}	
			if(flag){
				bool tmp=1;
				for(int i=2;i<=5;++i){//判断是不是10-A 
					if(a[i].data!=i+8)tmp=0;
				}
			 	if((a[2].data==a[1].data+1)||(tmp&&a[1].data==1))  flag=1;//是不是顺子 
				else flag=0;
			}
			if(!flag){//无对特判 
				for(int i=5;i>=1;--i){
					if(a[i].data==1) a[i].data=14;
				}
				sort(a+1,a+6,cmp);
				node tmp=find(a);
				Node ans;
				ans.col=tmp.col;
				ans.data=tmp.data;
				ans.num=9;
				return ans;
			}
			node tmp=find(a);
			Node ans;
			ans.col=tmp.col;
			if(a[1].data==1&&a[2].data!=2){//判断是不是10-A 
				ans.data=14;
				ans.col=a[1].col;
			} 
			else ans.data=tmp.data;
			ans.num=5;
			return ans;
		}else{
			bool flag=1;
			for(int i=1;i<5;++i){//判断2-5是不是连着的 
				if(a[i+1].data!=a[i].data+1) flag=0;
			}
			if(flag){
				bool tmp=1;
				for(int i=2;i<=5;++i){//判断是不是10-A 
					if(a[i].data!=i+8) tmp=0;
				}
			 	if((a[2].data==a[1].data+1)||(tmp&&a[1].data==1))  flag=1; //是不是顺子 
				else flag=0;
			}
			if(flag){//同花顺 
				node tmp=find(a);
				Node ans;
				ans.col=tmp.col;
				if(a[1].data==1&&a[2].data==2) ans.data=1;
				else if(a[1].data==1) ans.data=14;
				else ans.data=tmp.data;
				ans.num=1;
				return ans;
			}
			else{//同花 
				for(int i=1;i<=5;++i){//把1换成A无影响 
					if(a[i].data==1) a[i].data=14;
				}
				sort(a+1,a+6,cmp);
				node tmp=find(a);
				Node ans;
				ans.col=tmp.col;
				ans.data=tmp.data;
				ans.num=4;
				return ans;
			}
		}
	}
	else{//无对 
		for(int i=5;i>=1;--i){
			if(a[i].data==1) a[i].data=14;
		}
		sort(a+1,a+6,cmp);
		node tmp=find(a);
		Node ans;
		ans.col=tmp.col;
		ans.data=tmp.data;
		ans.num=9;
		return ans;
	}
}
bool judge(Node x1,Node y1){//判断谁赢 
	if(x1.num<y1.num) return true;
	else if(x1.num>y1.num) return false;
	else{
		if(x1.num==2||x1.num==3||x1.num==6){//四条,满堂红,三条特判 
			return b[3].data>c[3].data;//一定在中间 且不需要比较花色 
		}
		if(x1.num==4){//同花特判 
			for(int i=5;i>=1;--i){//单牌比较 
				if(b[i].data>c[i].data) return true;
				else if(b[i].data==c[i].data) continue;
				else return false;
			}
			if(x1.col>y1.col) return true;
			else return false;
		}
		if(x1.num==7){//两对特判 
			int tmp1=0;
			int tmp2=0;
			int tmp3=0;
			int tmp4=0;
			for(int i=1;i<5;++i){//第一副牌的两个对子 
				if(b[i].data==b[i+1].data){
					if(!tmp1)tmp1=i;
					else tmp3=i;
				} 
				if(c[i].data==c[i+1].data){//第二幅牌 
					if(!tmp2)tmp2=i;
					else tmp4=i;
				} 
			}
			if(b[tmp1].data<b[tmp3].data) swap(tmp1,tmp3);//保证1,2更大 
			if(b[tmp2].data<b[tmp4].data) swap(tmp2,tmp4);
			if(b[tmp1].data>c[tmp2].data) return true;//第一大的对子比较 
			else if(b[tmp1].data<c[tmp2].data) return false;
			else{
				if(b[tmp3].data>c[tmp4].data) return true;//第二大的对子比较 
				else if(b[tmp3].data<c[tmp4].data) return false;
				else{
					for(int i=5;i>=1;--i){//单牌比较 
						if(b[i].data>c[i].data) return true;
						else if(b[i].data==c[i].data) continue;
						else return false;
					}
					if(max(b[tmp1].col,b[tmp1+1].col)>max(b[tmp2].col,b[tmp2+1].col)) return true;//数码相同,颜色比较 
					else  return false;
				}
			
			}
		}
		else if(x1.num==8){//单对特判 
			int tmp1=0;
			int tmp2=0;
			for(int i=1;i<5;++i){//找对子 
				if(b[i].data==b[i+1].data) tmp1=i;
				if(c[i].data==c[i+1].data) tmp2=i;
			}
			if(b[tmp1].data>c[tmp2].data) return true;
			else if(b[tmp1].data<c[tmp2].data) return false;
			else{
				for(int i=5;i>=1;--i){
					if(b[i].data>c[i].data) return true;
					else if(b[i].data==c[i].data) continue;
					else return false;
				}
				if(b[tmp1].col>c[tmp2].col) return true;
				else return false;
			}
		}
		else if(x1.num==9){//散牌 
			for(int i=5;i>=1;--i){
				if(b[i].data>c[i].data) return true;
				else if(b[i].data==c[i].data) continue;
				else return false;
			}
			if(b[5].col>c[5].col) return true;//因为把A换成13所以比较最后一个 
			else return false;
		}
		else{//顺子可直接判断 
			if(x1.data>y1.data) return true;
			else if(x1.data<y1.data) return false;
			else{
				if(x1.col>y1.col) return true;
				else return false;
			}
		}
	}
} 
int main(){
	//freopen("ptgiving.in","r",stdin);
	//freopen("ptgiving.out","w",stdout);
	scanf("%d",&n);
	while(n--){
		for(int i=1;i<=5;++i){
			scanf("%d %d",&b[i].data,&b[i].col);
			b[i].col=5-b[i].col;//转化花色 
		}
		sort(b+1,b+6,cmp);
		Node tmp1=cheak(b);
		for(int i=1;i<=5;++i){
			scanf("%d %d",&c[i].data,&c[i].col);
			c[i].col=5-c[i].col;//转化花色 
		}
		sort(c+1,c+6,cmp);
		Node tmp2=cheak(c);
		if(judge(tmp1,tmp2)) printf("Alice\n");
		else printf("Mukyu\n");
	}
	return 0;
}

posted @ 2019-10-14 20:04  End_donkey  阅读(386)  评论(0编辑  收藏  举报