2014 Multi-University Training Contest 6 Fighting the Landlords

来源:互联网 发布:微博软件下载 编辑:程序博客网 时间:2024/05/16 01:55

题意:就是普通的斗地主,问你第一个人能不能打败第二个人

注意点:

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;}


0 0
原创粉丝点击