P5801 [SEERC 2019] Game on a Tree
\(\color{#3498db}9.4\) tag:【树】【博弈】【匹配】
Trick:树上博弈,考虑完美匹配。
以防读题读错了,这个题中的棋子可以移动到任意没走过的祖先节点,不只是父亲节点。
首先有一个类似的问题:假如棋子只能移动到相邻节点,考虑完美匹配的存在性:
- 如果存在完美匹配,先手不管选哪个点,后手都可以选它的匹配点,这样后手一直有点选,所以后手必胜;
- 否则先手可以选择一个非匹配点,显然其它点都是匹配点(不然就存在增广路,可以多一条匹配边),那么就变成了第一种情况,只不过先后手交换了,因此先手必胜。
这个题也差不多,区别在于 \(u\) 不仅可以和其相邻点匹配,还可以和它的任意祖先匹配,树形 dp,设 \(f_u\) 表示 \(u\) 子树内最少还剩多少个未匹配的点,转移是容易的。
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, f[N]; vector<int> G[N];
void dfs(int u, int fa) {for (int v : G[u]) if (v != fa) dfs(v, u), f[u] += f[v];if (f[u]) f[u]--; else f[u] = 1;
}
int main() {scanf("%d", &n);for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), G[u].push_back(v), G[v].push_back(u);dfs(1, 0), printf("%s", f[1] ? "Alice" : "Bob");
}