Cover the Tree

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]);
    }

}
posted @ 2020-07-14 00:53  ccsu_zhaobo  阅读(77)  评论(0编辑  收藏  举报