Solution S o l u t i o n
这是一个Undirected Vertex Geography。
可以
O(n3)
O
(
n
3
)
对每个点得到答案。
UVG游戏中
(G,v)
(
G
,
v
)
即图
G
G
中先手在 必胜的充要条件是
v
v
在所有最大匹配中。
证明:
- (充分性:)假设 在包含它的最大匹配
M
M
中:
- 如果他在必败态,则会走这样的路径 ,满足 v∈e1,ei∈M,fi∉M,i=1,2...,k v ∈ e 1 , e i ∈ M , f i ∉ M , i = 1 , 2... , k 。并且 fk=(x,y) f k = ( x , y ) ,其中 y y 不被 包含。设 A={e1,e2...,ek},B={f1,f2...,fk} A = { e 1 , e 2 . . . , e k } , B = { f 1 , f 2 . . . , f k } 一个直观的结论就是边集 M′=(M∖A)∪B M ′ = ( M ∖ A ) ∪ B 是一个不包含 v v 的匹配,且边数与 相同,即 M′ M ′ 不包含 v v ,与假设矛盾。
- (必要性:)假设存在最大匹配 不包含
v
v
:
- 如果他在必胜态,第一步走边 ,则
w
w
一定在最大匹配 中。则等价于后手在最大匹配
M
M
中必败,则会走这样的路径 ,满足
y
y
不被 包含。事实上我们得到了一个新的最大匹配
M′={e1,e2,...,ek+1}
M
′
=
{
e
1
,
e
2
,
.
.
.
,
e
k
+
1
}
,与假设矛盾。
考虑优化判断一个点是否一定在最大匹配中的方法。
注意到一个点 i i 一定在最大匹配中等价于所有最大流中 到该点 i i 的边有流量。
这个命题等价于:在某个最大流中 到 i i 的边有流量,且残量网络上不存在 到 i i <script type="math/tex" id="MathJax-Element-9398">i</script> 的路径。直接在残量网络里搜索就好啦。。。
#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; }
- 如果他在必胜态,第一步走边 ,则
w
w
一定在最大匹配 中。则等价于后手在最大匹配
M
M
中必败,则会走这样的路径 ,满足
y
y
不被 包含。事实上我们得到了一个新的最大匹配
M′={e1,e2,...,ek+1}
M
′
=
{
e
1
,
e
2
,
.
.
.
,
e
k
+
1
}
,与假设矛盾。