Loading

P6560 [SBCOI2020] 时光的流逝(DAG图上博弈模板)

P6560 [SBCOI2020] 时光的流逝(DAG图上博弈模板)

题意:

​ 给出一个有向图(可能有环),每轮游戏有一个起点和终点,A和B一起玩游戏。A先移动,然后他们交替移动,当谁把棋子移动至终点,谁就胜利了。同样,若是有人无法移动了,就会被判失败。若A必胜,输出1,若B必胜,输出-1,若两人均无必胜策略,输出0。

思路:

​ 很明显是一个博弈论。对于这种DAG上的博弈游戏,我们要从终点来考虑问题。分析题目,因为当棋子到达终点或者到达出度为0的点,此时执棋者失败。所以,终点和出度为0的点是必败态。这里把出度为0的点也归到下文终点的定义中。

​ 对于图上的博弈论,有一个很基础的知识点:若一个点可以到达必败态,那么这个点是必胜态。若一个点无法达到必败态,只能到达必胜态,那么这个点是必败态。

​ 因为我们一开始只知道终点的信息,所以我们应该建一个反图,然后从终点开始拓扑排序,根据上面的知识点进行模拟。

实现:

​ 在拓扑排序的时候要通过出度(反图的入度)来模拟判断一个点是否为必胜态。本题还有一个问题就是,什么叫均无必胜策略,那也就是遇到了一个环,比如simple2中的数据。我们在拓扑排序前对他们做标记,若拓扑排序做完之后,终点还没有进过队列,那就是环也就是输出0。

#include <bits/stdc++.h>

using namespace std;
#define rep(i, a, n) for (int i = a; i < n; i++)
#define all(x) x.begin(), x.end()
#define pb push_back
#define debug(x) cout << x << endl
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
string yes = "Yes\n";
string no = "No\n";

const int N = 100005;
int n, m, Q;
int d[N], f[N], back_d[N]; //入度会被更改,所以要备份一下。
vector<int> g[N];

int main()
{
    scanf("%d%d%d", &n, &m, &Q);
    while (m--)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        g[v].pb(u);
        d[u]++;
    }

    while (Q--)
    {
        int st, ed;
        scanf("%d%d", &st, &ed);
        queue<int> q;

        memcpy(back_d, d, sizeof back_d);
        for (int i = 1; i <= n; i++) //入度
        {
            if (i == ed || !back_d[i])
                f[i] = -1, q.push(i); // f --> Lose:-1  Win:1
            else
                f[i] = 0; //不可达就是0
        }

        while (q.size())
        {
            int u = q.front();
            q.pop();

            for (int v : g[u])
            {
                if (f[v] != 0)
                    continue;
                back_d[v]--;
                if (f[u] == -1) //如果一个点能走到一个必败点,那就是必胜态
                {
                    f[v] = 1;
                    q.push(v);
                }
                else if (!back_d[v])
                {
                    f[v] = -1;
                    q.push(v);
                }
            }
        }
        cout << f[st] << '\n';
    }
}
posted @ 2022-10-11 14:19  DM11  阅读(92)  评论(0编辑  收藏  举报