2020吉林省赛-Problem J. Situation(对抗搜索--记忆化搜索优化/alpha-beta优化)

题意:给你3x3的棋盘,初始时上面有一些棋子,‘O’代表Alice的棋子,‘X’代表Bob的棋子,‘.'代表还未放棋子,在所有空位都放上棋子后计算得分,如果Alice的棋子连成了一行一列或者是对角线则+1分(如果多行多列多条对角线都连成了一行,可叠加),如果是Bob的话就-1分。有多组测试用例,每组测试样例首先给出一个which,which==1代表Alice先下,which==0代表Bob先下,再给你3x3的初始棋盘,Alice想要最大化得分,Bob想要最小化得分,问最终得分是多少?

对抗搜索的算法大家可以看看这篇博客,我就是看这篇博客学会的,大概1小时就能掌握。

点击学习对抗搜索算法

本题测试组数有点多,需要加优化。

记忆化搜索优化 

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
typedef long long LL;
const int N=100010,M=2*N,mod=1e9+7,INF=0x3f3f3f3f;
char g[3][3];
map<int,int> f[2];//记录数组
int get()  //哈希,把状态映射成整数,可以看成长度为9的字符串,每位是’0‘,’1‘,’2‘中的一个,然后就可以看成是三进制转十进制
{
	int res=0;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			if(g[i][j]=='.') res=res*3;
			else if(g[i][j]=='O') res=res*3+1;
			else res=res*3+2;
	return res;
}
int cal()   //计算得分
{
	int score=0;
	for(int i=0;i<3;i++)
	{
		int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
		for(int j=0;j<3;j++)
		{
			if(g[i][j]=='O') cnt1++;
			else cnt2++;
			if(g[j][i]=='O') cnt3++;
			else cnt4++;
		}
		if(cnt1==3) score++;
		else if(cnt2==3) score--;
		if(cnt3==3) score++;
		else if(cnt4==3) score--;
	}
	int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
	for(int i=0;i<3;i++)
	{
		if(g[i][i]=='O') cnt1++;
		else cnt2++;
		if(g[i][2-i]=='O') cnt3++;
		else cnt4++;
		if(cnt1==3) score++;
		else if(cnt2==3) score--;
		if(cnt3==3) score++;
		else if(cnt4==3) score--;
	}
	return score;
}
int dfs(int cnt,int which)  //1取max,画O,0取min,画X
//cnt代表还有几个空位,which代表当前是谁操作
{
	int state=get();
	if(f[which].count(state)) return f[which][state];
	if(cnt==0) return cal();
	int ans=which?-INF:INF;
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			if(g[i][j]=='.')
			{
				g[i][j]=which?'O':'X';
				int t=dfs(cnt-1,!which);
				if(which) ans=max(ans,t);
				else ans=min(ans,t);
				g[i][j]='.';
			}
	return f[which][state]=ans;
}
int main()
{
	ios;
	int T;
	cin>>T;
	while(T--)
	{
		int which;
		f[0].clear(),f[1].clear();
		cin>>which;
		int cnt=0;
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				cin>>g[i][j],cnt+=(g[i][j]=='.');
		cout<<dfs(cnt,which)<<endl;
	}
	return 0;
}

Alpha-Beta优化

感觉写起来更简单,少了一步哈希映射,但是搜题解的时候大家都是用记忆化搜索来优化的,我试了下两种优化方式都是能ac的。

#include<bits/stdc++.h>
using namespace std;
#define ios ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl '\n'
typedef long long LL;
const int N=100010,M=2*N,mod=1e9+7,INF=0x3f3f3f3f;
char g[3][3];
int cal()
{
	int score=0;
	for(int i=0;i<3;i++)
	{
		int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
		for(int j=0;j<3;j++)
		{
			if(g[i][j]=='O') cnt1++;
			else cnt2++;
			if(g[j][i]=='O') cnt3++;
			else cnt4++;
		}
		if(cnt1==3) score++;
		else if(cnt2==3) score--;
		if(cnt3==3) score++;
		else if(cnt4==3) score--;
	}
	int cnt1=0,cnt2=0,cnt3=0,cnt4=0;
	for(int i=0;i<3;i++)
	{
		if(g[i][i]=='O') cnt1++;
		else cnt2++;
		if(g[i][2-i]=='O') cnt3++;
		else cnt4++;
		if(cnt1==3) score++;
		else if(cnt2==3) score--;
		if(cnt3==3) score++;
		else if(cnt4==3) score--;
	}
	return score;
}
int dfs(int cnt,int alpha,int beta,int which)  //1取max,画O,0取min,画X
{
	if(cnt==0) return cal();
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			if(g[i][j]=='.')
			{
				g[i][j]=which?'O':'X';
				int t=dfs(cnt-1,alpha,beta,!which);
				if(which==1) alpha=max(alpha,t);
				else beta=min(beta,t);
				g[i][j]='.';
				if(alpha>beta) break;
			}
	return which?alpha:beta;
}
int main()
{
	ios;
	int T;
	cin>>T;
	while(T--)
	{
		int which;
		cin>>which;
		int cnt=0;
		for(int i=0;i<3;i++)
			for(int j=0;j<3;j++)
				cin>>g[i][j],cnt+=g[i][j]=='.';
		cout<<dfs(cnt,-INF,INF,which)<<endl;
	}
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值