UVA1637 【纸牌游戏 Double Patience】
未经允许,请勿转载。
给大家分享一个神奇的做法:记忆化搜索
1.关于输入
像我这种特别讨厌字符串的当然是转换成\(int\)了,因为和花色不重要,只要把等级-'0'就OK了。
2.想直接暴搜怎么做:
每层dfs都有\(9\)个参数,代表每堆的数量。
在每层dfs直接双重循环 枚举去找 两堆最高层是 同等级 的情况,假设总共有\(sum\)种情况。
对于每种情况都先减去相应牌数,然后往下dfs,并把每一个情况返回的正确率都加起来。
最后把所有返回的胜率的和\((cnt)/sum\)就是这层dfs的胜率了。
特别注意的是:
当每一堆都是\(0\)时,返回\(1.0\) (就是胜率)
当\(sum=0\)时,直接返回\(0\)
3.处理记忆化
当然啦,这样直接暴搜是会\(TLE\)的,我们需要优化。
可以发现,在搜索时,可能同一种情况被搜索了\(INF\)次,因此,想到可以记忆化。
(注意神奇的地方来了).
用\(ans[][][][][][][][][]\)来存储每个情况的胜率。
因为胜率可能为0,所以在开一个\(bool\)数组\(a\)来判断是否搜索过。
oh对了,如果你jio的写太累了话,我给出两个建议:
1.复制黏贴
2.用宏定义
附上代码:(嘤嘤嘤)
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
bool a[5][5][5][5][5][5][5][5][5];//因为胜率可能为0,所以用一个数组来判断
double ans[5][5][5][5][5][5][5][5][5];//每种情况的胜率
int p[10][5];
double dfs(int p1,int p2,int p3,int p4,int p5,int p6,int p7,int p8,int p9)
{ if(a[p1][p2][p3][p4][p5][p6][p7][p8][p9])
return ans[p1][p2][p3][p4][p5][p6][p7][p8][p9];
a[p1][p2][p3][p4][p5][p6][p7][p8][p9]=1;
int t[15]={0,p1,p2,p3,p4,p5,p6,p7,p8,p9};
double cnt=0.0,sum=0.0;//胜率 总数
for(int i=1;i<=9;i++)//开始枚举
for(int j=i+1;j<=9;j++)
if(t[i]>0&&t[j]>0&&p[i][t[i]]==p[j][t[j]])//可以取这两堆的排
{ t[i]--;t[j]--;
sum++;
cnt+=dfs(t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8],t[9]);
t[i]++;t[j]++;
}
if(sum>0)ans[p1][p2][p3][p4][p5][p6][p7][p8][p9]=cnt/sum;
return ans[p1][p2][p3][p4][p5][p6][p7][p8][p9];//输了o(╥﹏╥)o
}
int main()
{ a[0][0][0][0][0][0][0][0][0]=1;
ans[0][0][0][0][0][0][0][0][0]=1.0;
for(int i=1;i<=9;i++)
{ string s1,s2,s3,s4;
cin>>s1>>s2>>s3>>s4;//众所周知花色不重要
p[i][1]=s1[0]-'0';
p[i][2]=s2[0]-'0';
p[i][3]=s3[0]-'0';
p[i][4]=s4[0]-'0';
//printf("%d %d %d %d\n",p[i][1],p[i][2],p[i][3],p[i][4]);
}
printf("%.6lf",dfs(4,4,4,4,4,4,4,4,4));
return 0;
}
by Rainy7