传送门:CCF201803-4 棋局评估
一道暴力搜索。由于两人都以最优策略行棋,故每当轮至1或2时,都对棋盘当前剩余的所有可走位置进行回溯dfs,以得出当前局面的最优结果。又因为1胜时得分为正,2胜时得分为负,故计算最值时,对1使用max,对2使用min。
下面是带注释的代码:
#include <bits/stdc++.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
int g[4][4];
bool read()
{
memset(g, 0, sizeof(g));
bool flag = false;
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j)
{
cin >> g[i][j];
if(g[i][j])
flag = true;
}
return flag;
}
int judge() //返回当前局面的胜者的编号
{
for(int i = 1; i <= 3; ++i)
{
if(g[i][1] != 0 && g[i][1] == g[i][2] && g[i][2] == g[i][3])
return g[i][1];
if(g[1][i] != 0 && g[1][i] == g[2][i] && g[2][i] == g[3][i])
return g[1][i];
}
if(g[2][2] != 0 && g[1][1] == g[2][2] && g[2][2] == g[3][3])
return g[2][2];
if(g[2][2] != 0 && g[1][3] == g[2][2] && g[2][2] == g[3][1])
return g[2][2];
return 0;
}
int dfs(int s) //s记录当前下棋者的编号
{
int sum = 0, win = judge();
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j)
if(!g[i][j])
sum++; //可走位置的数量
if(win == 1)
return sum+1; //1胜,返回1的得分
if(win == 2)
return -(sum+1); //2胜,返回2的得分
if(!sum)
return 0; //无位置可走,此时平局,两人得分都为0
int maxn = -INF, minn = INF;
for(int i = 1; i <= 3; ++i)
for(int j = 1; j <= 3; ++j)
if(!g[i][j])
{
g[i][j] = s; //s将棋下在这里
if(s == 1) //1走完,轮到2下
maxn = max(maxn, dfs(2)); //得到最优策略下的得分
if(s == 2)
minn = min(minn, dfs(1));
g[i][j] = 0; //回溯
}
if(s == 1)
return maxn;
if(s == 2)
return minn;
}
void solve()
{
if(!read())
{
cout << 0 << '\n'; //当棋盘为空时,特判
return;
}
else
cout << dfs(1) << '\n' ; //1先走棋
}
int main()
{
int t;
cin >> t;
while(t--)
solve();
return 0;
}