这题一眼看上去是一道树形DP的题目,然后后面一想好像可以用二分图来做(虽然是教练提醒的),故产生了此份题解。
题目大意
给定一个无根树,每个节点可以“管制”一堆给定点,求选择最少的点数来覆盖这棵树。
Solution
这题的“覆盖”看起来有那么亿点点像最小点覆盖,所以可以想想如何用二分图来解。
如何建立二分图?
注意到这是一棵树,则每层之间肯定不会有连接,而且没有跨越两层的边,所以我们可以把原图划分为奇数层和偶数层。
然后跑匈牙利貌似就可以了。
Tips:最小点覆盖数就是最大匹配数。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include <bits/stdc++.h> using namespace std;
const int N = 1505;
vector <int> G[N];
int n, ind, k, r; int ans, tot, dep[N], points[N];
bool vis[N];
void Pre (int k) { for (int i = 0; i < (int)G[k].size(); ++i) { int to = G[k][i]; if (vis[to]) continue ; vis[to] = true, dep[to] = dep[k] + 1; Pre(to); } }
int match[N];
bool DFS (int k) { for (int i = 0; i < (int)G[k].size(); ++i) { int to = G[k][i]; if (!vis[to]) { vis[to] = true; if (!match[to] || DFS(match[to])) { match[to] = k; return true; } } } return false; }
int main() { scanf("%d", &n); for (int Case = 0; Case ^ n; ++Case) { scanf("%d%d", &ind, &k); ++ind; for (int i = 0; i ^ k; ++i) { scanf("%d", &r); ++r; G[ind].push_back(r), G[r].push_back(ind); } } vis[1] = true, dep[1] = 1, Pre(1); for (int i = 1; i <= n; ++i) if (dep[i] % 2 == 1) points[++tot] = i; for (int i = 1; i <= tot; ++i) { memset(vis, false, sizeof(vis)); if (DFS(points[i])) ++ans; } printf("%d\n", ans); return 0; }
|