Cover the Tree
题意:
给定一棵无根树,你应该选择至少一条链覆盖树中所有边的最小链数。打印最小数量和一个解决方案。如果有多个解决方案,请打印其中任何一个
题解:
A:这题你怎么写的?
B:这题是个原题, cf出现过。
A:那怎么写呢?
B:贪心写吧!! 将所有叶子按照 dfs序排序 然后覆盖的边数就是 叶子节点数量 / 2 向上取整, 然后假设叶子节点数量是 k
第一个叶子节节点与 \(\frac{k}{2} + 1\)的叶子节点相连, 然后第二个就与\(\frac{k}{2} + 2\)的相连………………要是奇数的话最后一个就好第一个相连。
A:为啥这样就是最少呢?
B:至于为啥?这个我也不会证明, 但是可以简单的想一下, 第一个叶子节节点与 \(\frac{k}{2} + 1\)的相连 这两个节点lca一定是根节点或者根节点的儿子节点, 这样贪心就是最长的链。我就是这样想的, 至于严格的证明我还不会。
A: 好!
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 7;
vector<int> g[N];
vector<int> ans;
void dfs(int u, int fa) {
if (g[u].size() == 1) {
ans.push_back(u);
}
for (int to: g[u]) {
if (to == fa)continue;
dfs(to, u);
}
}
int main () {
int n; scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
int cnt = (int)ans.size();
if (cnt % 2 == 0) {
printf("%d\n", cnt / 2);
for (int i = 0; i < cnt / 2; i++) {
printf("%d %d\n", ans[i], ans[cnt / 2 + i]);
}
} else {
printf("%d\n", cnt / 2 + 1);
for(int i = 0; i < cnt / 2; i++) {
printf("%d %d\n", ans[i], ans[cnt / 2 + i]);
}
printf("%d %d\n", ans[0], ans[cnt - 1]);
}
}