Texas hold 'em - 模拟

传送门:https://jag2012autumn.contest.atcoder.jp/tasks/icpc2012autumn_b

一副去掉大小王的扑克牌,你和对手分别摸2张作为手牌,桌面上还有3张已经亮开的牌和2张未亮开的牌。

在亮开剩余2张牌后,你和对手分别从手牌+桌面上的牌这7张中选择5张,按规则进行比较,较大的一方获胜。

比较规则为:同花顺>四条>葫芦>同花>顺子>三条>两对>一对>散牌,同级别下再按照数量顺序比较点数大小(如四条就是先比较相同的4张的点数,再比较单张的点数)。

求:在剩余两张牌的所有可能情况下,你的获胜(打平不算)概率。

解法很简单粗暴,直接枚举剩余两张牌,注意不能与已知的7张牌相同,然后每个人再从7张中暴力枚举5张,剩下的就是如何比较两手牌的大小了。

一开始我是打算直接按照顺序比下去,发现如果这么写无异于进了无底洞,写了500多行还不知道怎么wa的……

果断弃坑,考虑到这个偏序关系满足传递性,因此我们可以用“赋分法”来做,就是给每手牌计算一个权值,然后就可以直接比较了。

计算权值的过程相比直接比较就简单得多了,详见代码。

#include<bits/stdc++.h>
using namespace std;
char c[5];
int m1[200],m2[200];
bool b[55]; 
struct pi{
	int hs,ds,bh;
	bool operator < (const pi &q) const{
		return ds > q.ds;
	}
	pi(){}
	pi(int q){
		bh = q;
		hs = q / 13;
		ds = q % 13;
	}
}p1[10],p2[10],p3[10],p4[10];
#define li long long
li mx1,mx2,mi[20];
li wk(pi *q){
	pi w[10];
	memcpy(w,q,sizeof(w));
	sort(w + 1,w + 6);
	for(int i = 1;i <= 5;++i) ++w[i].ds;
	//同花顺
	if(w[1].hs == w[2].hs && w[2].hs == w[3].hs && w[3].hs == w[4].hs && w[4].hs == w[5].hs){
		if(w[1].ds - w[2].ds == 1 && w[2].ds - w[3].ds == 1 && w[3].ds - w[4].ds == 1 && w[4].ds - w[5].ds == 1) return mi[15] * w[1].ds;
		if(w[1].ds == 13 && w[2].ds == 4 && w[3].ds == 3 && w[4].ds == 2 && w[5].ds == 1) return mi[15] * 4;
	}
	//四张
	if(w[2].ds == w[3].ds && w[3].ds == w[4].ds){
		if(w[1].ds == w[3].ds) return mi[14] * w[3].ds + w[5].ds;
		if(w[5].ds == w[3].ds) return mi[14] * w[3].ds + w[1].ds;
	} 
	//葫芦 
	if(w[1].ds == w[2].ds && w[4].ds == w[5].ds){
		if(w[3].ds == w[1].ds) return mi[13] * w[3].ds + w[5].ds;
		if(w[3].ds == w[5].ds) return mi[13] * w[3].ds + w[1].ds;
	}
	//同花
	if(w[1].hs == w[2].hs && w[2].hs == w[3].hs && w[3].hs == w[4].hs && w[4].hs == w[5].hs) return mi[12] * w[1].ds + mi[3] * w[2].ds + mi[2] * w[3].ds + mi[1] * w[4].ds + w[5].ds;
	//顺子
	if(w[1].ds - w[2].ds == 1 && w[2].ds - w[3].ds == 1 && w[3].ds - w[4].ds == 1 && w[4].ds - w[5].ds == 1) return mi[11] * w[1].ds;
	if(w[1].ds == 13 && w[2].ds == 4 && w[3].ds == 3 && w[4].ds == 2 && w[5].ds == 1) return mi[11] * 4;
	//三张
	if(w[1].ds == w[2].ds && w[2].ds == w[3].ds) return mi[10] * w[3].ds + mi[1] * w[4].ds + w[5].ds;
	if(w[2].ds == w[3].ds && w[3].ds == w[4].ds) return mi[10] * w[3].ds + mi[1] * w[1].ds + w[5].ds;
	if(w[3].ds == w[4].ds && w[4].ds == w[5].ds) return mi[10] * w[3].ds + mi[1] * w[1].ds + w[2].ds;
	//两对 
	if(w[1].ds == w[2].ds && w[3].ds == w[4].ds) return mi[9] * w[1].ds + mi[1] * w[3].ds + w[5].ds;
	if(w[1].ds == w[2].ds && w[4].ds == w[5].ds) return mi[9] * w[1].ds + mi[1] * w[5].ds + w[3].ds;
	if(w[2].ds == w[3].ds && w[4].ds == w[5].ds) return mi[9] * w[3].ds + mi[1] * w[5].ds + w[1].ds;
	//对子
	if(w[1].ds == w[2].ds) return mi[8] * w[1].ds + mi[2] * w[3].ds + mi[1] * w[4].ds + w[5].ds;
	if(w[2].ds == w[3].ds) return mi[8] * w[2].ds + mi[2] * w[1].ds + mi[1] * w[4].ds + w[5].ds;
	if(w[3].ds == w[4].ds) return mi[8] * w[3].ds + mi[2] * w[1].ds + mi[1] * w[2].ds + w[5].ds;
	if(w[4].ds == w[5].ds) return mi[8] * w[4].ds + mi[2] * w[1].ds + mi[1] * w[2].ds + w[3].ds;
	//散牌
	return mi[4] * w[1].ds + mi[3] * w[2].ds + mi[2] * w[3].ds + mi[1] * w[4].ds + w[5].ds;
}
bool chk(){
	mx1 = mx2 = 0;
	int i,j,k,l;
	for(i = 1;i <= 6;++i){
		for(j = i + 1;j <= 7;++j){
			l = 0;
			for(k = 1;k <= 7;++k) if(k != i && k != j){
				p3[++l] = p1[k];
				p4[l] = p2[k];
			} 
			mx1 = max(mx1,wk(p3));
			mx2 = max(mx2,wk(p4));
		}
	}
	return mx1 > mx2;
}
bool r(pi &q){
	scanf("%s",c);
	if(c[0] == '#') return 0;
	q = (pi)(m1[c[0]] * 13 + m2[c[1]]);
	return 1;
}
int main(){
	
	m1['S'] = 0;m1['H'] = 1;m1['D'] = 2;m1['C'] = 3;
	m2['2'] = 0;m2['3'] = 1;m2['4'] = 2;m2['5'] = 3;m2['6'] = 4;m2['7'] = 5;m2['8'] = 6;m2['9'] = 7;m2['T'] = 8;m2['J'] = 9;m2['Q'] = 10;m2['K'] = 11;m2['A'] = 12;
	int t2;
	int i,j;
	mi[0] = 1;
	for(i = 1;i <= 16;++i) mi[i] = mi[i - 1] * 14;
	while(1){
		memset(b,0,sizeof(b));
		if(!r(p1[1])) break;
		r(p1[2]);r(p2[1]);r(p2[2]);r(p1[3]);r(p1[4]);r(p1[5]);
		p2[3] = p1[3];p2[4] = p1[4];p2[5] = p1[5];
		b[p1[1].bh] = b[p1[2].bh] = b[p2[1].bh] = b[p2[2].bh] = b[p1[3].bh] = b[p1[4].bh] = b[p1[5].bh] = 1;
		t2 = 0;
		for(i = 0;i < 52;++i) if(!b[i]){
			for(j = i + 1;j < 52;++j) if(!b[j] && i != j){
				p1[6] = p2[6] = (pi)i;
				p1[7] = p2[7] = (pi)j;
				t2 += chk();
			}
		}
		printf("%.10lf\n",t2 / 990.0);
	}
	return 0;
}

写完之后闲得无聊,想想这么一个大模拟最后也不是太难写,那最短能写到多短呢?

于是就有了这个(前方高能):

#include<bits/stdc++.h>
#define R(a,b,c)for(_ a=b;a<=c;++a)
#define X(b,c)q[b].a==q[c].a&&
#define A(a,b)w[a]==w[b]
#define B(a,b)h[a]*w[b]
#define D(a,b,c,d,e)B(a,b)+B(c,d)+w[e]
using _=int;char a[5];_ b[99],c[99],d[99],w[9];__int64 f,g,h[20];struct e{_ a,b,c;e(){}e(_ q){c=q;a=q/13;b=q%13;}}p[9],q[9],r[9],s[9];__int64 n(e *q){R(i,1,5)w[i]=q[i].b+1;std::sort(w+1,w+6);_ u=X(5,4)X(4,3)X(3,2)X(2,1)1,v=w[5]-w[4]==1&&w[4]-w[3]==1&&w[3]-w[2]==1&&w[2]-w[1]==1,x=w[5]==13&&w[4]==4&&w[3]==3&&w[2]==2&&w[1]==1;return u&&v?B(12,5):u&&x?B(12,4):A(1,4)?B(11,3)+w[5]:A(2,5)?B(11,3)+w[1]:A(1,3)&&A(4,5)?B(10,3)+w[5]:A(1,2)&&A(3,5)?B(10,3)+w[1]:u?B(9,5)+B(3,4)+D(2,3,1,2,1):v?B(8,5):x?B(8,4):A(1,3)?D(7,3,1,5,4):A(2,4)?D(7,3,1,5,1):A(3,5)?D(7,3,1,2,1):A(1,2)&&A(3,4)?D(6,3,1,1,5):A(1,2)&&A(4,5)?D(6,5,1,1,3):A(2,3)&&A(4,5)?D(6,5,1,3,1):A(1,2)?B(5,1)+D(2,5,1,4,3):A(2,3)?B(5,2)+D(2,5,1,4,1):A(3,4)?B(5,3)+D(2,5,1,2,1):A(4,5)?B(5,4)+D(2,3,1,2,1):B(4,5)+B(3,4)+D(2,3,1,2,1);}bool o(){f=g=0;R(i,1,6)R(j,i+1,7){_ l=0;R(k,1,7)k^i&&k^j?r[++l]=p[k],s[l]=q[k]:0;f=f>n(r)?f:n(r);g=g>n(s)?g:n(s);}return f>g;}bool z(e &q){scanf("%s",a);return a[0]==35?0:(q=b[a[0]]*13+c[a[1]],d[q.c]=1);}main(){b[83]=0,b[72]=1,b[68]=2,b[67]=3,c[84]=8,c[74]=9,c[81]=10,c[75]=11,c[65]=12;R(i,2,9)c[i+48]=i-2;h[0]=1;R(i,1,12)h[i]=h[i-1]*14;while(1){memset(d,0,sizeof(d));if(!z(p[1]))break;z(p[2]);z(q[1]);z(q[2]);z(p[3]);z(p[4]);z(p[5]);q[3]=p[3],q[4]=p[4],q[5]=p[5];_ t=0;R(i,0,50)R(j,i,51)!d[i]&&!d[j]&&i^j?p[6]=q[6]=i,p[7]=q[7]=j,t+=o():0;printf("%.9lf\n",t/990.0);}}
1535B可还行。(顺便%一发压到984B的_rqy)

猜你喜欢

转载自blog.csdn.net/liuzhangfeiabc/article/details/80855228
EM