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

posted @ 2020-02-01 21:39  Rainy7  阅读(159)  评论(0编辑  收藏  举报