Codeforces 786A Berzerk 题解 [ 绿 ] [ 有向图博弈论 ] [ BFS ]

Berzerk:有向图博弈论板子。

注意到怪物位置的状态数很少,于是考虑图论建模。因为有两个人轮流操作,所以需要建成分层图的形式,每次顺时针移动 \(x\) 的位置相当于向另一层连边。当走到任意一层编号为 \(1\) 的点或走到出度为 \(0\) 的点的时候,先手必败。

这就成一个很典的有向图博弈论问题了,直接建反图,从终止状态的胜负情况拓展到所有状态的胜负情况即可。具体地:

  • 当一个点的出点有先手必败点时,该点先手必胜。
  • 当一个点的出点全是先手必胜点时,该点先手必败。
  • 否则,该点为平局点。

从终止状态 BFS 即可,途中记录每个点的度数,以便对第二种情况进行判断。注意不能显式建图,空间会炸掉。

时间复杂度 \(O(m)\),其中 \(m = n^2\),因为本题的 BFS 复杂度和边数有关。

#include <bits/stdc++.h>
#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 = 7005;
int n, na, a[N], nb, b[N], du[2][N], st[2][N];
queue<pi> q;
int main()
{
    //freopen("sample.in", "r", stdin);
    //freopen("sample.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    cin >> na;
    for(int i = 1; i <= na; i++) cin >> a[i];
    cin >> nb;
    for(int i = 1; i <= nb; i++) cin >> b[i];
    for(int i = 1; i <= n; i++)
    {
        du[0][i] = na;
        du[1][i] = nb;
    }
    st[0][1] = st[1][1] = -1;
    q.push({0, 1});
    q.push({1, 1});
    while(!q.empty())
    {
        pi cur = q.front();
        q.pop();
        int u = cur.se, lv = cur.fi;
        if(lv == 0)
        {
            for(int i = 1; i <= nb; i++)
            {
                int v = u - b[i];
                if(v <= 0) v += n;
                if(st[lv ^ 1][v]) continue;
                if(st[lv][u] == -1)
                {
                    st[lv ^ 1][v] = 1;
                    q.push({lv ^ 1, v});
                }
                else
                {
                    du[lv ^ 1][v]--;
                    if(du[lv ^ 1][v] == 0)
                    {
                        st[lv ^ 1][v] = -1;
                        q.push({lv ^ 1, v});
                    }
                }
            }
        }
        else
        {
            for(int i = 1; i <= na; i++)
            {
                int v = u - a[i];
                if(v <= 0) v += n;
                if(st[lv ^ 1][v]) continue;
                if(st[lv][u] == -1)
                {
                    st[lv ^ 1][v] = 1;
                    q.push({lv ^ 1, v});
                }
                else
                {
                    du[lv ^ 1][v]--;
                    if(du[lv ^ 1][v] == 0)
                    {
                        st[lv ^ 1][v] = -1;
                        q.push({lv ^ 1, v});
                    }
                }
            }            
        }
    }
    for(int i = 2; i <= n; i++)
    {
        if(st[0][i] == 0) cout << "Loop ";
        else if(st[0][i] == 1) cout << "Win ";
        else cout << "Lose ";
    }
    cout << "\n";
    for(int i = 2; i <= n; i++)
    {
        if(st[1][i] == 0) cout << "Loop ";
        else if(st[1][i] == 1) cout << "Win ";
        else cout << "Lose ";
    }    
    return 0;
}
posted @ 2025-08-26 15:47  KS_Fszha  阅读(8)  评论(0)    收藏  举报