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,记忆化搜索)

每日dp Gym - 101889E Enigma 数位dp 记忆化搜索

Luogu_P1514 引水入城 记忆化搜索

CSU 1592 石子归并(记忆化搜索 or 区间DP)

记忆化搜索