Luogu P9169 [省选联考 2023] 过河卒 题解 [ 紫 ] [ 博弈论 ] [ BFS ] [ 模拟 ] [ 卡常 ]

过河卒:也是吃上伊思倍思的陈年老史了。

显然是一个有向图博弈论问题。如果某个点的出边有一个指向先手必败点,则这个点是先手必胜点;如果某个点的出边全都指向先手必胜点,则这个点是先手必败点;否则这个点是平局点。于是把所有终止状态丢进队列里,在反图上跑 BFS 即可。

进一步考虑如何最大化失败的步数 / 最小化成功的步数。观察 BFS 的实现,设两个点 \(u,v\) 满足 \(u\) 更新 \(v\) 的状态为先手必胜 / 必败点;不难发现当 \(v\) 为先手必胜点时,\(u\) 一定是第一个更新 \(v\) 的点;当 \(v\) 为先手必败点时,\(u\) 一定是最后一个更新 \(v\) 的点。恰好与题目中的限制相符,所以边 BFS 记录一下距离即可。

剩下的就是模拟建图了,细节很多,需要注意以下几点:

  • 红子在四个方向上都能移动。
  • 红子不能相撞
  • 黑子向上、左、右移动。
  • 红子黑子都不能越界或者碰到障碍。
  • BFS 是在反图上跑的。
  • 多测清空。

终止状态有如下几种:

  • 黑子在第一行,此时(红子的轮)先手必败。
  • 红子黑子同位置,先手必败。
  • 无法进行操作(出度为 \(0\)),先手必败。

有一些卡常技巧:

  • 必须显式建图,否则在 BFS 的时候再枚举会显著增加常数。
  • 加火车头。
  • BFS 的时候给每个点分配编号。
  • 手动实现队列。
  • 剪掉无用或重复状态,例如钦定 \(rx_1 \le rx_2\),否则该状态剪掉。注意循环的时候也需要剪这一部分的枝,不然还是会 TLE。
  • 开 C++23。

时间复杂度 \(O(Tn^3m^3)\)。写了 11KB,火车头是抄了 TLEWA 的。

#pragma GCC diagnostic push
#pragma G++ diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wattributes"
#pragma G++ diagnostic ignored "-Wpragmas"
#pragma G++ diagnostic ignored "-Wattributes"
#pragma G++ optimize(1)
#pragma G++ optimize(2)
#pragma G++ optimize(3)
#pragma G++ optimize("Ofast")
#pragma G++ optimize("inline")
#pragma G++ optimize("-fgcse")
#pragma G++ optimize("-fgcse-lm")
#pragma G++ optimize("-fipa-sra")
#pragma G++ optimize("-ftree-pre")
#pragma G++ optimize("-ftree-vrp")
#pragma G++ optimize("-ffast-math")
#pragma G++ optimize("-fsched-spec")
#pragma G++ optimize("-fdevirtualize")
#pragma G++ optimize("-fcaller-saves")
#pragma G++ optimize("-fschedule-insns")
#pragma G++ optimize("inline-functions")
#pragma G++ optimize("-ftree-tail-merge")
#pragma G++ optimize("-fschedule-insns2")
#pragma G++ optimize("-fstrict-aliasing")
#pragma G++ optimize("-fstrict-overflow")
#pragma G++ optimize("-fcse-skip-blocks")
#pragma G++ optimize("-fcse-follow-jumps")
#pragma G++ optimize("-fsched-interblock")
#pragma G++ optimize("-fpartial-inlining")
#pragma G++ optimize("no-stack-protector")
#pragma G++ optimize("-frerun-cse-after-loop")
#pragma G++ optimize("inline-small-functions")
#pragma G++ optimize("-finline-small-functions")
#pragma G++ optimize("-ftree-switch-conversion")
#pragma G++ optimize("-foptimize-sibling-calls")
#pragma G++ optimize("-findirect-inlining")
#pragma G++ optimize("-fexpensive-optimizations")
#pragma G++ optimize("-faggressive-loop-optimizations")
#pragma G++ optimize("inline-functions-called-once")
#pragma G++ optimize("-fdelete-null-pointer-checks")
#pragma G++ optimize("-fomit-frame-pointer")
#pragma G++ optimize("-fno-semantic-interposition")
#pragma G++ optimize("-freciprocal-math")
#pragma G++ optimize("tree-vectorize")
#pragma G++ optimize("move-loop-invariants")
#pragma G++ optimize("branch-target-load-optimize")
#pragma G++ optimize("btr-bb-exclusive")
#pragma G++ optimize("predictive-commoning")
#pragma G++ optimize("gcse-sm")
#pragma G++ optimize("gcse-las")
#pragma G++ optimize("ipa-pta") 
#pragma G++ optimize("ipa-ra")
#pragma G++ optimize("ipa-cp")
#pragma G++ optimize("ipa-bit-cp")
#pragma G++ optimize("ipa-vrp")
#pragma G++ optimize("ipa-sra")
#pragma G++ optimize("prefetch-loop-arrays")
#pragma G++ optimize("-fmodulo-sched")
#pragma G++ optimize("-freschedule-modulo-scheduled-loops")
#pragma G++ optimize("-fselective-scheduling")
#pragma G++ optimize("-fsel-sched-pipelining")
#pragma G++ optimize("-fsel-sched-pipelining-outer-loops")
#ifdef __GNUC__
#define force_inline (__attribute__((always_inline)))
#else
#define force_inline [[gnu::always_inline]]
#endif
#include<bits/stdc++.h>
#pragma GCC target("sse3","sse2","sse","sse4","sse4.1","sse4.2","ssse3","f16c","fma","avx2","xop","fma4","mmx","popcnt","tune=native","abm")
#pragma G++ target("sse3","sse2","sse","sse4","sse4.1","sse4.2","ssse3","f16c","fma","avx2","xop","fma4","mmx","popcnt","tune=native","abm")
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 11, V = 2000005;
const int bgox[] = {1, 0, 0};
const int bgoy[] = {0, 1, -1};
const int rgox[] = {0, 0, 1, -1};
const int rgoy[] = {1, -1, 0, 0};
int n, m, du[V], q[V], hd, tl, cid[2][N][N][N][N][N][N];
char s[N][N];
int st[V], dis[V];
int h[V], idx;
struct Edge{
    int v, ne;
}e[40000005];
void add(int u, int v)
{
    e[++idx] = {v, h[u]};
    h[u] = idx;
}
bool legal(int r, int bx, int by, int rx1, int ry1, int rx2, int ry2)
{
    if(bx < 0 || rx1 < 0 || rx2 < 0) return 0;
    if(by < 0 || ry1 < 0 || ry2 < 0) return 0;
    if(bx >= n || rx1 >= n || rx2 >= n) return 0;
    if(by >= m || ry1 >= m || ry2 >= m) return 0;
    if(s[bx][by] == '#') return 0;
    if(s[rx1][ry1] == '#') return 0;
    if(s[rx2][ry2] == '#') return 0;
    if(rx1 == rx2 && ry1 == ry2) return 0;
    return 1;
}
void BFS()
{
    while(tl - hd >= 0)
    {
        int u = q[hd++];
        for(int i = h[u]; i ; i = e[i].ne)
        {
            int v = e[i].v;
            if(st[v] != -1) continue;
            if(st[u] == 0)
            {
                st[v] = 1;
                dis[v] = dis[u] + 1;
                q[++tl] = v;
            }
            else
            {
                du[v]--;
                if(du[v] == 0)
                {
                    st[v] = 0;
                    dis[v] = dis[u] + 1;
                    q[++tl] = v;
                }
            }            
        }
    }
}
void solve()
{
    cin >> n >> m;
    idx = 0;
    for(int i = 0; i <= 2 * n * m * n * m * n * m; i++)
    {
        st[i] = -1;
        dis[i] = h[i] = du[i] = 0;
    }
    for(int i = 0; i < n; i++) cin >> s[i];
    int curid = 0;
    for(int r = 0; r <= 1; r++)
        for(int bx = 0; bx < n; bx++)
            for(int by = 0; by < m; by++)
                for(int rx1 = 0; rx1 < n; rx1++)
                    for(int ry1 = 0; ry1 < m; ry1++)
                        for(int rx2 = rx1; rx2 < n; rx2++)
                            for(int ry2 = 0; ry2 < m; ry2++)
                                cid[r][bx][by][rx1][ry1][rx2][ry2] = curid++;
    hd = 1;
    tl = 0;
    for(int r = 0; r <= 1; r++)
        for(int bx = 0; bx < n; bx++)
            for(int by = 0; by < m; by++)
                for(int rx1 = 0; rx1 < n; rx1++)
                    for(int ry1 = 0; ry1 < m; ry1++)
                        for(int rx2 = rx1; rx2 < n; rx2++)
                            for(int ry2 = 0; ry2 < m; ry2++)
                            {
                                if(!legal(r, bx, by, rx1, ry1, rx2, ry2)) continue;
                                int id = cid[r][bx][by][rx1][ry1][rx2][ry2];
                                if(r == 0)
                                {
                                    for(int i = 0; i < 4; i++)
                                    {
                                        int tx = rx1 + rgox[i], ty = ry1 + rgoy[i];
                                        bool flag = 0;
                                        if(tx > rx2)
                                        {
                                            swap(tx, rx2);
                                            swap(ty, ry2);
                                            flag = 1;
                                        }
                                        if(legal(r ^ 1, bx, by, tx, ty, rx2, ry2))
                                        {
                                            add(cid[r ^ 1][bx][by][tx][ty][rx2][ry2], id);
                                            du[id]++;
                                        }
                                        if(flag)
                                        {
                                            swap(tx, rx2);
                                            swap(ty, ry2);
                                        }
                                    }
                                    for(int i = 0; i < 4; i++)
                                    {
                                        int tx = rx2 + rgox[i], ty = ry2 + rgoy[i];
                                        bool flag = 0;
                                        if(rx1 > tx)
                                        {
                                            swap(tx, rx1);
                                            swap(ty, ry1);
                                            flag = 1;
                                        }
                                        if(legal(r ^ 1, bx, by, rx1, ry1, tx, ty))
                                        {
                                            add(cid[r ^ 1][bx][by][rx1][ry1][tx][ty], id);
                                            du[id]++;
                                        }
                                        if(flag)
                                        {
                                            swap(tx, rx1);
                                            swap(ty, ry1);
                                        }
                                    }
                                }
                                else
                                {
                                    for(int i = 0; i < 3; i++)
                                    {
                                        int tx = bx - bgox[i], ty = by + bgoy[i];
                                        bool flag = 0;
                                        if(rx1 > rx2)
                                        {
                                            swap(rx2, rx1);
                                            swap(ry2, ry1);
                                            flag = 1;
                                        }
                                        if(legal(r ^ 1, tx, ty, rx1, ry1, rx2, ry2))
                                        {
                                            add(cid[r ^ 1][tx][ty][rx1][ry1][rx2][ry2], id);
                                            du[id]++;
                                        }
                                        if(flag)
                                        {
                                            swap(rx2, rx1);
                                            swap(ry2, ry1);
                                        }
                                    }
                                }
                                if(bx == 0)
                                {
                                    if(r == 0)
                                    {
                                        st[id] = dis[id] = 0;
                                        q[++tl] = id;
                                    }
                                    continue;
                                }
                                if((bx == rx1 && by == ry1) || (bx == rx2 && by == ry2))
                                {
                                    st[id] = dis[id] = 0;
                                    q[++tl] = id;
                                    continue;
                                }
                                if(du[id] == 0)
                                {
                                    st[id] = dis[id] = 0;
                                    q[++tl] = id;
                                }
                            }
    BFS();
    int bx, by, rx1 = -1, ry1 = -1, rx2, ry2;
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            if(s[i][j] == 'X')
                bx = i, by = j;
            if(s[i][j] == 'O')
            {
                if(rx1 == -1)
                    rx1 = i, ry1 = j;
                else
                    rx2 = i, ry2 = j;
            }
        }
    } 
    if(rx1 > rx2)
    {
        swap(rx1, rx2);
        swap(ry1, ry2);
    }
    int ans1 = st[cid[0][bx][by][rx1][ry1][rx2][ry2]], ans2 = dis[cid[0][bx][by][rx1][ry1][rx2][ry2]];
    if(ans1 == -1) cout << "Tie\n";
    else if(ans1 == 0) cout << "Black " << ans2 << "\n";
    else cout << "Red " << ans2 << "\n";
}
int main()
{
    //freopen("sample.in", "r", stdin);
    //freopen("sample.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int id, t;
    cin >> id >> t;
    while(t--) solve();
    return 0;
}
posted @ 2025-08-25 21:10  KS_Fszha  阅读(14)  评论(0)    收藏  举报