洛谷P4055 [JSOI2009] 游戏 二分图博弈

题目链接:https://www.luogu.com.cn/problem/P4055

二分图博弈 先手必胜 的结论:

\(\dagger\) 先手必胜当且仅当起点 \(u\) 在该二分图的所有最大匹配上。

解题思路:完全来自 hopeful_imitation大佬的博客

其核心结论(文字的最后一段,代码上方):

\(\dagger\) 如果一个点 \(P\) 已被证实是细点,设它有一边连着 \(Q\),且 \(Q\) 在最大匹配上,则 \(Q\) 的匹配点也是细点。

代码实现时是先跑的 匈牙利算法,然后再配合上面的结论解决的。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e3 + 5;

int N, M, n, m, id[105][105], idx1, idx2;
pair<int, int> pos1[maxn], pos2[maxn];
char s[105][105];
int dir[4][2] = {-1, 0, 1, 0, 0, -1, 0, 1};
vector<int> g[maxn], rg[maxn];
vector<pair<int, int>> ans;

bool in_map(int x, int y) {
    return x >= 0 && x < N && y >= 0 && y < M;
}

bool vis[maxn];
int mat1[maxn], mat2[maxn];

bool dfs(int u) {
    for (auto &v : g[u]) {
        if (!vis[v]) {
            vis[v] = true;
            if (!mat2[v] || dfs(mat2[v])) {
                mat2[v] = u;
                mat1[u] = v;
                return true;
            }
        }
    }
    return false;
}

bool vis1[maxn], vis2[maxn];

void dfs1(int u) {
    if (vis1[u])
        return;
    vis1[u] = true;
    for (auto &v : g[u]) {
        if (mat2[v])
            dfs1(mat2[v]);
    }
}

void dfs2(int u) {
    if (vis2[u])
        return;
    vis2[u] = true;
    for (auto &v : rg[u]) {
        if (mat1[v])
            dfs2(mat1[v]);
    }
}

int main() {
    scanf("%d%d", &N, &M);
    for (int i = 0; i < N; i++)
        scanf("%s", s[i]);
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            if (s[i][j] == '#')
                continue;
            int x = (i + j) % 2;
            if (x) {
                id[i][j] = ++n;
                pos1[n] = {i, j};
            }
            else {
                id[i][j] = ++m;
                pos2[m] = {i, j};
            }
        }
    }
    for (int x = 0; x < N; x++) {
        for (int y = 0; y < M; y++) {
            if (s[x][y] == '#')
                continue;
            if (! ( (x+y) % 2 ))
                continue;
            for (int i = 0; i < 4; i++) {
                int xx = x + dir[i][0], yy = y + dir[i][1];
                if (in_map(xx, yy) && s[xx][yy] != '#') {
                    int u = id[x][y], v = id[xx][yy];
                    g[u].push_back(v);
                    rg[v].push_back(u);
                }
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        fill(vis+1, vis+m+1, false);
        dfs(i);
    }
    for (int i = 1; i <= n; i++) {
        if (!mat1[i] && !vis1[i])
            dfs1(i);
    }
    for (int i = 1; i <= m; i++) {
        if (!mat2[i] && !vis2[i])
            dfs2(i);
    }
    for (int i = 1; i <= n; i++)
        if (vis1[i])
            ans.push_back(pos1[i]);
    for (int i = 1; i <= m; i++)
        if (vis2[i])
            ans.push_back(pos2[i]);
    if (ans.size() == 0) {
        puts("LOSE");
    }
    else {
        puts("WIN");
        sort(ans.begin(), ans.end(), [](auto a, auto b) {
            if (a.first != b.first)
                return a.first < b.first;
            return a.second < b.second;
          });
        for (auto [x, y] : ans)
            printf("%d %d\n", x+1, y+1);
    }

    return 0;
}
posted @ 2026-04-28 15:27  quanjun  阅读(9)  评论(0)    收藏  举报