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