AT_icpc2012autumn_b Texas hold'em题解

· · 题解

Link

怎么还有德扑的,不会打。

你是职业选手吗?我觉得我是。

我的大体思路是多用几个结构体。卡牌有结构体,准备出的5张牌也有结构体,对于后者比较麻烦,我在里面放了一个opt来表示其属于哪种等级,还放了若干函数来判断是哪种牌型。

主函数则直接枚举剩下的两张的取值,然后7选5排下序,两边各出最强牌。

排序的cmp函数写的比较长(

另外实现了一个按字典序比较两个vector的函数,感觉会比较方便。

写了6.5K,感觉还行。长但是好写。

code

const int N=15;

bool t[1000];

struct card{//牌
    int c,w;
    card(){c=w=0;}
    bool operator<(card ano)const{
        return w>ano.w;
    }
    void mkcard(char *ss){//制作卡牌
        if(ss[1]=='C')
            c=1;
        if(ss[1]=='D')
            c=2;
        if(ss[1]=='H')
            c=3;
        if(ss[1]=='S')
            c=4;
        if(ss[2]=='T')
            w=10;
        else if(ss[2]=='J')
            w=11;
        else if(ss[2]=='Q')
            w=12;
        else if(ss[2]=='K')
            w=13;
        else if(ss[2]=='A')
            w=14;
        else
            w=ss[2]-'0';
        t[c*15+w]=1;
    }
}my[N],ur[N];

struct handin{//准备要出的5张牌,姑且称为手牌
    int opt;//牌型
    card p[7];//牌
    bool samecol(){//是否同花
        bool tag=1;
        for(int i=2;i<=5;i++)
            tag&=p[i].c==p[1].c;
        return tag;
    }
    int continuous(){//是否是顺子(注意特判皇家顺)
        if(p[5].w==2&&p[4].w==3&&p[3].w==4&&p[2].w==5&&p[1].w==14)
            return 1;
        bool tag=1;
        for(int i=2;i<=5;i++)
            tag&=p[i].w==p[i-1].w-1;
        return (int)tag+(tag&&(p[1].w==14));
    }
    bool four(){//是否有炸弹
        map<int,int>mp;
        for(int i=1;i<=5;i++)
            mp[p[i].w]++;
        for(auto i:mp){
            if(i.se==4)
                return 1;
        }return 0;
    }
    bool three(){//是否有三张
        map<int,int>mp;
        for(int i=1;i<=5;i++)
            mp[p[i].w]++;
        for(auto i:mp){
            if(i.se==3)
                return 1;
        }return 0;
    }
    int two(){//有几对
        int num=0;
        map<int,int>mp;
        for(int i=1;i<=5;i++)
            mp[p[i].w]++;
        for(auto i:mp){
            num+=i.se==2;
        }return num;
    }
    void load_handin(){//加载牌型
        sort(p+1,p+6);
        if(samecol()&&continuous())//同花顺&皇家同花顺 
            opt=8+continuous();
        else if(four())//炸弹 
            opt=8;
        else if(three()&&two())//三带二 
            opt=7;
        else if(samecol())//同花 
            opt=6;
        else if(continuous())//顺子 
            opt=5;
        else if(three())//三 
            opt=4;
        else if(two()==2)//两对 
            opt=3;
        else if(two()==1)//一对 
            opt=2;
        else//散牌
            opt=1;
    }
};

bool compare_less(handin a,handin b){//比较两个vector
    for(int i=1;i<=5;i++)
        if(a.p[i].w!=b.p[i].w)
            return a.p[i].w>b.p[i].w;
    return 0;
}

bool cmp(handin a,handin b){//比较两组牌谁更大,值得注意的是两组牌都是已经按照数字大小排过序的了(在load_handin函数里)
    if(a.opt!=b.opt)//不同牌型
        return a.opt>b.opt;
    else{
        handin x,y;
        map<int,int> mpa,mpb;
        for(int i=1;i<=5;i++)
            mpa[a.p[i].w]++,mpb[b.p[i].w]++;
        if(a.opt==10)//皇家同花顺 
            return 0;
        else if(a.opt==9){//同花顺
            if(a.p[1].w==14)//因为一定不是皇家同花顺,那么这里的14就是1,只要有出现就说明是最小顺子
                return 0;
            else if(b.p[1].w==14)
                return 1;
            else
                return a.p[1].w>b.p[1].w;
        }else if(a.opt==8){//炸弹 
            for(auto i:mpa){
                if(i.se==4)
                    x.p[1].w=i.fi;//优先比炸弹谁大
                else
                    x.p[2].w=i.fi;
            }
            for(auto i:mpb){
                if(i.se==4)
                    y.p[1].w=i.fi;
                else
                    y.p[2].w=i.fi;
            }
            return compare_less(x,y);
        }else if(a.opt==7){//三带二 
            for(auto i:mpa){
                if(i.se==3)
                    x.p[1].w=i.fi;//优先比3张谁大
                else
                    x.p[2].w=i.fi;
            }
            for(auto i:mpb){
                if(i.se==3)
                    y.p[1].w=i.fi;
                else
                    y.p[2].w=i.fi;
            }
            return compare_less(x,y);
        }else if(a.opt==6){//同花 直接比
            return compare_less(a,b); 
        }else if(a.opt==5){//顺子 注意区分皇家顺与最小顺的14地位
            if(a.continuous()!=b.continuous())
                return a.continuous()>b.continuous();
            if(a.p[1].w==14)
                return 0;
            else if(b.p[1].w==14) 
                return 1;
            else
                return a.p[1].w>b.p[1].w;
        }else if(a.opt==4){//三 
            int nw=4;
            for(auto i:mpa){
                if(i.se==3)
                    x.p[1].w=i.fi;//先比3
                else
                    x.p[--nw].w=i.fi;//其次比最大的单牌,在遍历map的时候是先小后大,所以要反过来放
            }
            nw=4;
            for(auto i:mpb){
                if(i.se==3)
                    y.p[1].w=i.fi;
                else
                    y.p[--nw].w=i.fi;
            }
            return compare_less(x,y);
        }else if(a.opt==3){//两对 
            int nw=3;
            for(auto i:mpa){
                if(i.se==2)//先比大对子在比小对子最后单牌
                    x.p[--nw].w=i.fi;
                else
                    x.p[3].w=i.fi;
            }
            nw=3;
            for(auto i:mpb){
                if(i.se==2)
                    y.p[--nw].w=i.fi;
                else
                    y.p[3].w=i.fi;
            }
            return compare_less(x,y);
        }else if(a.opt==2){//一对 
            int nw=5;
            for(auto i:mpa){
                if(i.se==2)
                    x.p[1].w=i.fi;//先比对子再比最大单,次大单,最小单
                else
                    x.p[--nw].w=i.fi;
            }
            nw=5;
            for(auto i:mpb){
                if(i.se==2)
                    y.p[1].w=i.fi;
                else
                    y.p[--nw].w=i.fi;
            }
            return compare_less(x,y);
        }else
            return compare_less(a,b);//单牌直接挨个比
    }
}

void readin(){
    char ys1[N],ys2[N],os1[N],os2[N];
    char tbll[4][N];
    scanf("%s",ys1+1);
    if(ys1[1]=='#')
        exit(0);
    scanf("%s%s%s",ys2+1,os1+1,os2+1);
    for(int i=1;i<=3;i++)
        scanf("%s",tbll[i]+1);
    my[1].mkcard(ys1);
    my[2].mkcard(ys2);
    ur[1].mkcard(os1);
    ur[2].mkcard(os2);
    my[3].mkcard(tbll[1]);
    my[4].mkcard(tbll[2]);
    my[5].mkcard(tbll[3]);
    ur[3].mkcard(tbll[1]);
    ur[4].mkcard(tbll[2]);
    ur[5].mkcard(tbll[3]);//制作卡牌
}

handin tmp[1000];

signed main(){
    while(1){
        memset(t,0,sizeof(t));
        readin();
        int sum=0,win=0;
        for(int ic=1;ic<=4;ic++){
            for(int iw=2;iw<=14;iw++){//枚举第一张牌
                if(t[ic*15+iw])
                    continue;
                t[ic*15+iw]=1;
                my[6].c=ic,my[6].w=iw;
                ur[6].c=ic,ur[6].w=iw;
                for(int jc=1;jc<=4;jc++){
                    for(int jw=2;jw<=14;jw++){//第二张
                        if(t[jc*15+jw])
                            continue;
                        my[7].c=jc,my[7].w=jw;
                        ur[7].c=jc,ur[7].w=jw;
                        handin mygo,urgo;//两人准备要出的牌
                        int all=(1<<7)-1;
                        int tot=0;
                        for(int k=1;k<=all;k++){
                            if(__builtin_popcount(k)==5){
                                int nw=0;
                                ++tot;
                                for(int j=1;j<=7;j++)
                                    if(k&(1<<(j-1)))
                                        tmp[tot].p[++nw]=my[j];
                                tmp[tot].load_handin();
                            }
                        }
                        sort(tmp+1,tmp+1+tot,cmp);
                        mygo=tmp[1];
                        tot=0;
                        for(int k=1;k<=all;k++){
                            if(__builtin_popcount(k)==5){
                                int nw=0;
                                ++tot;
                                for(int j=1;j<=7;j++)
                                    if(k&(1<<(j-1)))
                                        tmp[tot].p[++nw]=ur[j];
                                tmp[tot].load_handin();
                            }
                        }
                        sort(tmp+1,tmp+1+tot,cmp);
                        urgo=tmp[1];
                        win+=cmp(mygo,urgo);//直接比较即可
                        sum++;
                    }
                }
                t[ic*15+iw]=0;
            }
        }
//      cout<<win<<" "<<sum<<endl;
        printf("%.10lf\n",1.0*win/sum);
    }
    return 0;
}