gym102800J记忆化搜索(对抗搜索)
Posted hesorchen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了gym102800J记忆化搜索(对抗搜索)相关的知识,希望对你有一定的参考价值。
题目
https://codeforces.com/gym/102800/attachments
一个3*3的棋盘残局,有三种字符:
- 字符
.
表示此处还未下棋。 - 字符
O
表示这是Alice的棋。 - 字符
X
表示这是Bob的棋。
注意,所给的残局不一定是合法的残局,也即可能一方的棋子更多。
当一方的棋连成三个时(可以斜着、横着、竖着),此人得一分。最后棋盘下满后,这局游戏的得分为:Alice的分数-Bob的分数。
现在,输入1表示Alice先手、0表示Bob先手,双方轮流下棋。Alice想要得分最大,Bob想要得分最小,双方都最优的策略下,问这局的最后得分是多少?
Sample Input 1 | Sample Input 2
0 | 1
.OO | XXX
X.O | XXX
OXO | XXX
|
Sample Output 1 | Sample Output 2
2 | -8
解题思路
将地图哈希成一个数值,最多有 3 9 3^9 39张地图,不到20000,暴力枚举所有情况即可,使用记忆化搜索剪枝。
AC代码
#include <bits/stdc++.h>
using namespace std;
unordered_map<string, int> num;
string pre[20010];
int id; //20000
int dp[20010][2]; // 地图i 轮到j
void get_id(string a)
{
if (a.size() == 9)
{
num[a] = ++id;
pre[id] = a;
return;
}
get_id(a + '.');
get_id(a + 'O');
get_id(a + 'X');
}
int get_score(string &a)
{
int res = 0;
if (a[0] == a[1] && a[1] == a[2])
res += a[1] == 'O' ? 1 : -1;
if (a[3] == a[4] && a[4] == a[5])
res += a[4] == 'O' ? 1 : -1;
if (a[6] == a[7] && a[7] == a[8])
res += a[7] == 'O' ? 1 : -1;
if (a[0] == a[3] && a[3] == a[6])
res += a[3] == 'O' ? 1 : -1;
if (a[1] == a[4] && a[4] == a[7])
res += a[4] == 'O' ? 1 : -1;
if (a[2] == a[5] && a[5] == a[8])
res += a[5] == 'O' ? 1 : -1;
if (a[0] == a[4] && a[4] == a[8])
res += a[4] == 'O' ? 1 : -1;
if (a[2] == a[4] && a[4] == a[6])
res += a[4] == 'O' ? 1 : -1;
return res;
}
int dfs(int st, int opt)
{
string s = pre[st];
if (dp[st][opt] != -1)
return dp[st][opt];
int mm = 10, mx = -10, flag = 0;
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
{
if (s[(i - 1) * 3 + j - 1] == '.')
{
flag = 1;
s[(i - 1) * 3 + j - 1] = (opt ? 'O' : 'X');
int temp = dfs(num[s], opt ^ 1);
s[(i - 1) * 3 + j - 1] = '.';
mm = min(mm, temp);
mx = max(mx, temp);
}
}
if (!flag)
return dp[st][opt] = get_score(s);
if (opt == 1)
return dp[st][opt] = mx;
else
return dp[st][opt] = mm;
}
char ss[50];
int main()
{
memset(dp, -1, sizeof dp);
get_id("");
dfs(1, 1);
dfs(1, 0);
int t;
scanf("%d", &t);
while (t--)
{
int opt;
scanf("%d", &opt);
for (int i = 0; i < 3; i++)
scanf("%s", ss + i * 3);
string aa = "";
for (int i = 0; i < 9; i++)
aa += ss[i];
cout << dfs(num[aa], opt) << endl;
}
return 0;
}
以上是关于gym102800J记忆化搜索(对抗搜索)的主要内容,如果未能解决你的问题,请参考以下文章
P4363 [九省联考2018]一双木棋chess(对抗搜索+记忆化搜索)
Loppinha, the boy who likes sopinha Gym - 101875E (dp,记忆化搜索)