E. 机智的学姐 2014新生暑假个人排位赛05
题目描述
斗地主玩法简单,娱乐性强,老少皆宜。据传在万恶的旧社会,地主横行乡里,无恶不做,人们为了发泄对地主的痛恨,常常在一天的劳作之后,一家人关起门来“斗地主”。该游戏由三人玩一副牌,地主为一方,其余两家为另一方,双方对战,先出完手中牌的一方胜。
机智的学姐已经通过某些不和谐的手段,得到了下家手上的牌型,可是学姐的机智值全都用来得到下家牌型了。她非常想知道自己是不是有一种出牌的方法,使得下家没有办法能大过自己,这个艰难的任务就交给你了。(不用判断输赢,只需判断这一轮牌有没有好的策略使下家没法大过自己)
关于牌型比较
火箭:即双王(大王和小王),最大的牌。
炸弹:四张同数值牌(如四个7)。
单牌:单个牌(如一张5)。
对牌:数值相同的两张牌(如一对4)。
三张牌:数值相同的三张牌(如三个J)。
三带一:数值相同的三张牌 + 一张单牌或一对牌。例如:333+6 或 444+99。
单顺:五张或更多的连续单牌(如:45678 或 78910JQK)。不包括 2 点和双王。
双顺:三对或更多的连续对牌(如:334455 、77 88 99 1010 JJ)。不包括 2 点和双王。
三顺:二个或更多的连续三张牌(如:333444 、 555 666 777 888)。不包括 2 点和双王。
飞机带翅膀:三顺+同数量的单牌(或同数量的对牌)。
如: 444555+79 或 333444555+7799JJ。
四带二:四张牌+两手牌(注意:四带二不是炸弹)。
如: 5555+3+8 或 4444+55+77。
关于牌型大小
火箭最大,可以打任意其他的牌。
炸弹比火箭小,比其他牌大。都是炸弹时按牌的分值比大小。
除火箭和炸弹外,其他牌必须要牌型相同且总张数相同才能比大小。相同牌型按牌的分值比大小。
依次是 大王 > 小王 >2>A>K>Q>J>10>9>8>7>6>5>4>3 ,不分花色。
输入格式
为了处理方便,我们用Y表示大王,X表示小王,T表示10。
所有牌都用A23456789TJQKXY表示,两家牌的数量小于20。
每组数据两行,有多组数据,EOF结束。
输出格式
每个测试数据一行Yes或者No
输入样例
A334455
23456789
23456
456789
AJJJ
3333
输出样例
Yes
Yes
No
思路:这题给你上家的牌,让你判断下家的牌有没有大过他的。首先可以预处理出上下家手里的牌,然后对每一种出牌方式枚举,若存在一种出牌方式下家没有大过他的就为Yes,
若扫描完所有情况都有打过它的就为No.
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define LOCAL
using namespace std;
char str1[50],str2[50];
struct type
{
int sg[16];//单牌
int cp[14];//对牌
int tp[14][3];//三张牌
int sgs[13][9];//单顺
int cps[11][11];//双顺
int tps[7][12][3];//三顺
int bomb[14][3];//炸弹
}A,B;
void Init(type &x,char str[])
{
int i,j,k,len=strlen(str);
memset(&x,0,sizeof(x));
for(int i=0;i<len;i++)//处理单牌
{
int t;
if(str[i]>='3'&&str[i]<='9')t=str[i]-'2';
else if(str[i]=='T')t=8;
else if(str[i]=='J')t=9;
else if(str[i]=='Q')t=10;
else if(str[i]=='K')t=11;
else if(str[i]=='A')t=12;
else if(str[i]=='2')t=13;
else if(str[i]=='X')t=14;
else if(str[i]=='Y')t=15;
x.sg[t]++;
if(x.sg[0]<t)x.sg[0]=t;/**/
}
for(int i=1;i<=13;i++)//处理对牌,三张牌,炸弹
{
if(x.sg[i]>1)
{
x.cp[i]=1;
x.cp[0]=i;
}
if(x.sg[i]>2)
{
x.tp[i][0]=1;
x.tp[0][0]=i;
}
if(x.sg[i]>3)
{
x.bomb[i][0]=1;
x.bomb[0][0]=i;
}
}
for(i=1;i<=13;i++)//处理三带一,三带二
{
if(x.tp[i][0]==0)continue;
for(j=1;j<=15;j++)
{
if(j==i)continue;
if(x.sg[j])
{
x.tp[i][1]=1;
x.tp[0][1]=i;
break;
}
}
for(j=1;j<=13;j++)
{
if(j==i)continue;
if(x.cp[j])
{
x.tp[i][2]=1;
x.tp[0][2]=i;
break;
}
}
}
for(i=1;i<=8;i++)//小五张
if(x.sg[i]&&x.sg[i+1]&&x.sg[i+2]&&x.sg[i+3]&&x.sg[i+4])
{
x.sgs[5][i]=1;
x.sgs[5][0]=i;
}
for(i=6;i<=12;i++)//大于五张
for(j=1;i+j-1<=12;j++)
if(x.sgs[i-1][j]&&x.sg[i+j-1])
{
x.sgs[i][j]=1;
x.sgs[i][0]=j;
}
for(i=1;i<=10;i++)//三对
if(x.cp[i]&&x.cp[i+1]&&x.cp[i+2])
{
x.cps[3][i]=1;
x.cps[3][0]=i;
}
for(i=4;i<=12;i++)//大于三对
for(j=1;i+j-1<=12;j++)
if(x.cps[i-1][j]&&x.cp[i+j-1])
{
x.cps[i][j]=1;
x.cps[i][0]=j;
}
for(i=1;i<=11;i++)//两个三组
if(x.tp[i][0]&&x.tp[i+1][0])
{
x.tps[2][i][0]=1;
x.tps[2][0][0]=i;
}
for(i=3;i<=6;i++)//大于两个三组
for(j=1;i+j-1<=12;j++)
if(x.tps[i-1][j][0]&&x.tp[i+j-1][0])
{
x.tps[i][j][0]=1;
x.tps[i][0][0]=j;
}
for(i=2;i<=6;i++)//飞机
{
for(j=1;i+j-1<=12;j++)
{
if(x.tps[i][j][0]==0)continue;
int cnt=0;
for(k=1;k<=15;j++)
{
if(k>=j&&k<=i+j-1)continue;
if(x.sg[j])cnt+=x.sg[j];
if(cnt>=i)
{
x.tps[i][j][1]=1;
x.tps[i][0][1]=j;
break;
}
}
cnt=0;
for(k=1;k<=13;k++)
{
if(k>=j&&k<=i+j-1)continue;
if(x.cp[j])cnt++;
if(cnt==i)
{
x.tps[i][j][2]=1;
x.tps[i][0][2]=j;
break;
}
}
}
}
}
int main()
{
#ifdef LOCAL
freopen("input.txt","r",stdin);
#endif // LOCAL
while(scanf("%s%s",str1,str2)==2)
{
Init(A,str1);
Init(B,str2);
if(A.sg[14]&&A.sg[15])//若同时有大王小王,则必没有可以大过他的。反之亦然。
{
printf("Yes\n");
continue;
}
else if(B.sg[14]&&B.sg[15])
{
printf("No\n");
continue;
}
if(A.bomb[0][0]>=B.bomb[0][0]&&A.bomb[0][0]>0)//若A持有的最大的炸弹比B大且不等于0,则必无法大过A,反之亦然
{
printf("Yes\n");
continue;
}
if(A.bomb[0][0]<B.bomb[0][0])
{
printf("No\n");
continue;
}
if((A.sg[0]>=B.sg[0]&&A.sg[0])||(A.cp[0]>=B.cp[0]&&A.cp[0])||(A.tp[0][0]>=B.tp[0][0]&&A.tp[0][0])||(A.tp[0][1]>=B.tp[0][1]&&A.tp[0][1])||(A.tp[0][2]>=B.tp[0][2]&&A.tp[0][2]))//若A持有的最大的单牌,对牌,三张牌,三带一,三带二比大于等于B且不为0则必没有大过的
{
printf("Yes\n");
continue;
}
int flag=0;
for(int i=5;i<=12;i++)
if(A.sgs[i][0]>=B.sgs[i][0]&&A.sgs[i][0])//若A存在i个单顺的最大大于B的i个单顺最大则标记能大于等于B且不为0,跳出
{
flag=1;
break;
}
for(int i=3;i<=10;i++)
if(A.cps[i][0]>=B.cps[i][0]&&A.cps[i][0])//若A存在i个双顺的最大大于B的i个双顺最大则标记能大于等于B且不为0,跳出
{
flag=1;
break;
}
for(int i=2;i<=6;i++)
if((A.tps[i][0][0]>=B.tps[i][0][0]&&A.tps[i][0][0])||(A.tps[i][0][1]>=B.tps[i][0][1]&&A.tps[i][0][1])||(A.tps[i][0][2]>=B.tps[i][0][2]&&A.tps[i][0][2]))//若A存在i个三顺的最大大于B的i个三顺最大则标记能大于等于B且不为0或A存在i个飞机带翅膀的最大大于B的i个飞机带翅膀最大则标记能大于等于B且不为0,跳出
{
flag=1;
break;
}
if(flag==1)
{
printf("Yes\n");
continue;
}
else
{
printf("No\n");
continue;
}
}
return 0;
}