這是一個Undirected Vertex Geography。
可以 對每個點得到答案。
UVG遊戲中 即圖 中先手在 必勝的充要條件是 在所有最大匹配中。
證明:
- (充分性:)假設 在包含它的最大匹配 中:
- 如果他在必敗態,則會走這樣的路徑 ,滿足 。並且 ,其中 不被 包含。設 一個直觀的結論就是邊集 是一個不包含 的匹配,且邊數與 相同,即 不包含 ,與假設矛盾。
- (必要性:)假設存在最大匹配 不包含 :
- 如果他在必勝態,第一步走邊 ,則 一定在最大匹配 中。則等價於後手在最大匹配 中必敗,則會走這樣的路徑 ,滿足 不被 包含。事實上我們得到了一個新的最大匹配 ,與假設矛盾。
考慮優化判斷一個點是否一定在最大匹配中的方法。
注意到一個點 一定在最大匹配中等價於所有最大流中 到該點 的邊有流量。
這個命題等價於:在某個最大流中 到 的邊有流量,且殘量網絡上不存在 到 的路徑。
直接在殘量網絡裏搜索就好啦。。。
#include <bits/stdc++.h>
#define show(x) cerr << #x << " = " << x << endl
using namespace std;
typedef long long ll;
typedef pair<int, int> Pairs;
const int N = 1010101;
const int INF = 1 << 30;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0; int sgn = 0;
for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1;
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
if (sgn) x = -x;
}
struct edge {
int to, cap, next;
edge(int t = 0, int c = 0, int n = 0): to(t), cap(c), next(n) {}
};
edge G[N << 1];
int head[N], cur[N], dis[N], vis[N];
int id[N], ans[N];
int m, c, n1, n2, gcnt, s, t, clc, ncnt, x, y;
queue<int> Q;
inline void addEdge(int from, int to, int cap) {
G[++gcnt] = edge(to, cap, head[from]); head[from] = gcnt;
G[++gcnt] = edge(from, 0, head[to]); head[to] = gcnt;
}
inline int bfs(int s, int t) {
vis[s] = ++clc;
Q.push(s); dis[s] = 0;
while (!Q.empty()) {
int x = Q.front(); Q.pop();
for (int i = head[x]; i; i = G[i].next) {
edge &e = G[i];
if (e.cap && vis[e.to] != clc) {
dis[e.to] = dis[x] + 1;
Q.push(e.to); vis[e.to] = clc;
}
}
}
return vis[t] == clc;
}
inline int dfs(int u, int a) {
if (u == t || a == 0) return a;
int flow = 0, f;
for (int &i = cur[u]; i; i = G[i].next) {
edge &e = G[i];
if (e.cap && dis[e.to] == dis[u] + 1
&& (f = dfs(e.to, min(a, e.cap))) > 0) {
e.cap -= f; G[i ^ 1].cap += f;
flow += f; a -= f;
if (a == 0) break;
}
}
return flow;
}
inline int maxFlow(int s, int t) {
int flow = 0;
while (bfs(s, t)) {
for (int i = 0; i <= ncnt; i++) cur[i] = head[i];
flow += dfs(s, INF);
}
return flow;
}
inline void dfs(int u) {
vis[u] = clc; ans[id[u]] = 0;
for (int i = head[u]; i; i = G[i].next) {
edge &e = G[i];
if (e.cap < 0 && !vis[e.to])
dfs(e.to);
}
}
int main(void) {
gcnt = 1;
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
read(m); read(c); ncnt = m + c;
s = ++ncnt; t = ++ncnt;
read(n1);
for (int i = 1; i <= n1; i++) {
ans[i] = 1;
read(x); read(y);
addEdge(s, ++ncnt, 1);
addEdge(ncnt, x, 1);
addEdge(ncnt, m + y, 1);
id[ncnt] = i;
}
read(n2);
for (int i = 1; i <= n2; i++) {
read(x); read(y);
addEdge(x, ++ncnt, 1);
addEdge(m + y, ncnt, 1);
addEdge(ncnt, t, 1);
}
maxFlow(s, t);
for (int i = head[s]; i; i = G[i].next)
if (G[i].cap == 1)
ans[id[G[i].to]] = 0;
for (int i = 1; i <= ncnt; i++)
if (vis[i] == clc)
ans[id[i]] = 0;
for (int i = 1; i <= n1; i++)
printf("%d\n", ans[i]);
return 0;
}