题意:就是普通的斗地主,问你第一个人能不能打败第二个人
注意点:
1.三张牌出牌带的必须的一对,而四张牌带的可以是两张不同的
2.第一个人打完牌他就赢了,不用考虑后面的人
思路:
一共有8种出牌方法,前面6种只能按照牌面大小打败相同的出牌类型
但是最后两种,也是就玩炸和炸弹可以打败其他的出牌类型;
因此,我们考虑计算出每一个出牌类型,能出的最大的权重,
如果是最后两种就把他们的权重更新到其他6种出牌类型里面
最后统计的时候要注意的是:
1.第一个人的某一种出牌类型为0的时候不能比较,因为如果第二个人这一种出牌类型的最大权重也为0也就是说,他不能出这种牌,用大于等于判断的时候就会出错
2.第二个人出光手牌的情况不能被考虑,因为第二个人只能出与第一个人对应的出牌类型.
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <vector> using namespace std; const int Bomb=1e6; //炸弹的权重 const int Nuke=1e7;//玩炸的权重 const int EMPTY_HAND=1e9;//一次能光打牌的权重 bool is_first;//是否是第一个人 int card[16],apro[7],bpro[7];//各种权重卡片的个数,a的各种出牌类型的最大权重,b的各种出牌类型的最大权重 int *pro;//当前计算时权重的存储位置 int prio_ch(char a) //卡牌权重转换函数,从小到大 { switch(a) { case 'Y': return 15; case 'X': return 14; case '2': return 13; case 'A': return 12; case 'K': return 11; case 'Q': return 10; case 'J': return 9; case 'T': return 8; case '9': case '8': case '7': case '6': case '5': case '4': case '3': return a-'0'-2; } } void setv(int i,int v) //用v更新i类型出牌的最大权重 { pro[i]=max(pro[i],v); } void setall(int v) //用v更新全部类型出牌的最大权重 { if(!is_first && v==EMPTY_HAND) return ; //如果不是第一个人打光手牌的话则返回 for(int i=1;i<=6;i++) pro[i]=max(pro[i],v); } void cal(string a) { memset(card,0,sizeof(card));//初始化 int n=a.size(),npair=0; for(int i=0;i<n;i++) card[prio_ch(a[i])]++; //计数 if(card[15] && card[14]) //大小王都有就更新全部出牌类型为玩炸 setall(Nuke); if(n==1) //只有一张牌,所以可以打光 setall(EMPTY_HAND); for(int i=1;i<=15;i++) //计算只出一张牌,也就是第一种出牌类型的权重 { if(card[i]) setv(1,i); } for(int i=1;i<=15;i++) //第二种出牌类型的权重 { if(card[i]>=2) { npair++; //计算不同对子的个数 setv(2,i); } } if(npair!=0 && n==2) //打一对就可以打完 setall(EMPTY_HAND); int ntri=0; //三张一样的对数 for(int i=1;i<=15;i++) //计算第三,四,五种出牌类型的权重 { if(card[i]>=3) //有三张以上 { ntri++; setv(3,i); if(n-card[i]>=1) //出了三张,至少还有一张是不同的 setv(4,i); if(npair>=2) //出了这三张,还可以出一对,因为3这本身三张也算是一对,所以要大于等于2 setv(5,i); } } if((n==3 && ntri==1) || (n==5 && ntri==3 && npair==2)) //一次出三张就打完了,或者 一次出5张 ,就是三张带一对 setall(EMPTY_HAND); if(ntri==1 && n==4) setall(EMPTY_HAND); //三张带一条 int ntrio=0; //四张一起的 for(int i=1;i<=15;i++) { if(card[i]==4) { ntrio++; setall(Bomb+i); //更新全部出牌类型炸弹,因为炸弹是可以当成任意出牌类型的 if(n>=6) setv(6,i); //出四张 ,加两张,注意这两张可以是不同的 } } if((n==4 && ntrio==1) || (ntrio==1 && n==6)) //出四张带一张,还有,带两张 setall(EMPTY_HAND); } int main() { // freopen("in","r",stdin); // freopen("out","w",stdout); int T; scanf("%d", &T); while(T--) { string a,b; cin>>a>>b; memset(apro,0,sizeof(apro)); memset(bpro,0,sizeof(bpro)); is_first=true; //第一个先手 pro=apro; cal(a); is_first=false;//不是先手 pro=bpro; cal(b); bool win=false; for(int i=1; i<=6; i++) { if(apro[i] && apro[i]>=bpro[i]) //某一种出牌的权重大于第二个人就可以赢了 { win=true; break; } } puts(win?"Yes":"No"); } return 0; }