洛谷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;
}
浙公网安备 33010602011771号