做过博弈论的题,做过概率DP的题,可是没有见过这样的题目。。
要开两个数组进行记忆化搜索。
其实一部分原因也是因为题目没有描述清楚(误,其实是自己没有看清楚比大小的规则)
规则是首先是闲家叫牌,不断的叫牌,然后轮到庄家叫牌,不断的叫牌,当庄家不叫牌时,就开始比大小
不是在电视里看过的那种庄家闲家来回轮流的叫牌。。。。
在正确理解规则的情况下,整个只有两个回合,一个是闲家叫牌,闲家要让自己的胜率最大,轮到庄家叫牌的时候,庄家会让闲家的胜率最小
定义状态dp[0][i][j]表示闲家i点,庄家j点,此时是闲家操作的闲家胜率
dp[1][i][j]表示闲家i点,庄家j点,此时是庄家操作的庄家胜率
状态转移方程在代码里面看吧,注意的是在庄家操作的时候假若庄家不叫牌了,就进入了比大小的环节
博弈DP,其实仔细分析,变化也不是很大,只是换了一个套路而已
#include <iostream>#include <cstring>#include <algorithm>#include <cctype>#include <string>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]);}
新闻热点
疑难解答