题意:给4个字符,字符为"A234566789TJQK"中之一,表示扑克的点数,当然A=1,T=J=Q=K=10。前两个字符是闲家的牌,后两个字符是庄家的牌。玩法是21点的规则(闲家先选择是否加牌--可多张,然后庄家选择是否加牌--可多张),超过21点直接算输,都加完后点数大赢。求最后闲家获胜的概率是否大于0.5,输出YES/NO。
分析:因为出题人说了没种牌的概率为1/13,即不会随着牌少而改变,变得简单了。我们要求的是最后闲家点数是否大于庄家,所以我们可以设状态f[i][j]表示闲家可加牌时闲家获胜的概率,dp[i][j]表示轮到庄家加牌时闲家获胜的概率。很明显我们可以用dfs先求出dp[i][j]整个数组来,而且f[i][j]的求解是依赖于dp[i][j]的,因为闲家拿完牌的边界是庄家开始拿牌即dp[i][j],所以我们同样用dfs处理f[i][j],并且要保证f[i][j]是拿与不拿之间的最大概率。
代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1000010;
const int MAX=151;
const int MOD=1000007;
const int MOD1=100000007;
const int MOD2=100000009;
const int INF=1000000000;
const double EPS=0.00000001;
typedef long long ll;
typedef unsigned long long ull;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
char s[5];
int z[130],bo[22][22],vis[22][22];
double h[22],dp[22][22],f[22][22];
double dfs(int x,int y) {
if (y>21) return 0;
if (x<=y) return 1;
double ret=0;
for (int i=1;i<=13;i++) ret+=dfs(x,y+min(i,10))/13;
return ret;
}
double get(int x,int y) {
if (x>21) return 0;
if (vis[x][y]) return f[x][y];
double &ret=f[x][y];
vis[x][y]=1;ret=0;
for (int i=1;i<=13;i++) ret+=get(x+min(i,10),y)/13;
return ret=max(ret,dp[x][y]);
}
void deal() {
int i,j;
for (i=1;i<22;i++)
for (j=1;j<22;j++) dp[i][j]=1-dfs(i,j);
memset(vis,0,sizeof(vis));
for (i=1;i<22;i++)
for (j=1;j<22;j++)
if (get(i,j)>0.5) bo[i][j]=1;
else bo[i][j]=0;
}
int main()
{
int i,t,x,y;
z['A']=1;z['2']=2;z['3']=3;z['4']=4;z['5']=5;
z['6']=6;z['7']=7;z['8']=8;z['9']=9;z['T']=10;
z['J']=10;z['Q']=10;z['K']=10;
deal();
scanf("%d", &t);
while (t--) {
scanf("%s", s);
x=z[s[0]]+z[s[1]];y=z[s[2]]+z[s[3]];
if (bo[x][y]) printf("YES\n");
else printf("NO\n");
}
return 0;
}