题意:给你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;
}