做过博弈论的题,做过概率DP的题,可是没有见过这样的题目。。
要开两个数组进行记忆化搜索。
其实一部分原因也是因为题目没有描述清楚(误,其实是自己没有看清楚比大小的规则)
规则是首先是闲家叫牌,不断的叫牌,然后轮到庄家叫牌,不断的叫牌,当庄家不叫牌时,就开始比大小
不是在电视里看过的那种庄家闲家来回轮流的叫牌。。。。
在正确理解规则的情况下,整个只有两个回合,一个是闲家叫牌,闲家要让自己的胜率最大,轮到庄家叫牌的时候,庄家会让闲家的胜率最小
定义状态dp[0][i][j]表示闲家i点,庄家j点,此时是闲家操作的闲家胜率
dp[1][i][j]表示闲家i点,庄家j点,此时是庄家操作的庄家胜率
状态转移方程在代码里面看吧,注意的是在庄家操作的时候假若庄家不叫牌了,就进入了比大小的环节
博弈DP,其实仔细分析,变化也不是很大,只是换了一个套路而已
#include
#include
#include
#include
#include
using namespace std;
const int maxm=35;
inline int p(char c){return (c=='A')?1:((isdigit(c)?c-'0':10));}
bool vis[2][maxm][maxm];
double dp[2][maxm][maxm],dfs0(int a,int b),dfs1(int a,int b);
int times;
string str;
int main(){
ios_base::sync_with_stdio(false);
cin>>times;
while(times--){
cin>>str;
cout<<(dfs0(p(str[0])+p(str[1]),p(str[2])+p(str[3]))>0.5?"YES\n":"NO\n");
}
return 0;
}
double dfs0(int a, int b){
if(a>21)
return 0;
else if(vis[0][a][b])
return dp[0][a][b];
vis[0][a][b]=true;
dp[0][a][b]=dfs1(a,b);
double tmp=0;
for(int i=1;i<10;++i)
tmp+=dfs0(a+i,b)/13;
tmp+=dfs0(a+10,b)*4/13;
return dp[0][a][b]=max(dp[0][a][b],tmp);
}
double dfs1(int a,int b){
if(b>21)
return 1;
else if(vis[1][a][b])
return dp[1][a][b];
vis[1][a][b]=true;
dp[1][a][b]=a>b;
double tmp=0;
for(int i=1;i<10;++i)
tmp+=dfs1(a,b+i)/13;
tmp+=dfs1(a,b+10)*4/13;
return dp[1][a][b]=min(tmp,dp[1][a][b]);
}