C-Cover the Tree(2020牛客暑期多校训练营(第二场))(找规律)
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld
链接:https://ac.nowcoder.com/acm/contest/5667/C
来源:牛客网
题目描述
Given an unrooted tree, you should choose the minimum number of chains that all edges in the tree are covered by at least one chain. Print the minimum number and one solution. If there are multiple solutions, print any of them.
输入描述:
The first line contains one integer
, denoting the size of the tree.
Following
lines each contains two integers
, denoting an edge in the tree.
It’s guaranteed that the given graph forms a tree.
输出描述:
The first line contains one integer
, denoting the minimum number of chains to cover all edges.
Following
lines each contains two integers
, denoting a chain you have chosen. Here
is permitted, which covers no edge.
输入
5
1 2
1 3
2 4
2 5
输出
2
2 3
4 5
题解
题意是给你一颗树,让你选出其中的一些链,使得这些链能够覆盖树上的所有的边,链与链之间可以彼此交叉重叠。
首先我们选出的每条链的两端一定都是叶子节点,如果不是叶子节点的话一定可以使链条继续向外扩展延长以便覆盖更多的边。所以问题就变成了如何选出多干个叶子节点对,使得他们的路径覆盖所有的边,叶子节点可以重复选择,路径也可以彼此交叉重叠。
然后可以参考官方题解,比我讲得好:
下面给出图示配合证明。
假设有如下树:
随即选出一个边a,a的儿子节点覆盖的叶子节点区间为[L, R]。
当
时,这条边会被
覆盖。
例如:
否则当
时,这条边会被
覆盖。
例如:
否则因为根节点度数不为1,所以
中必有一个是满足的,如果
则这条边会被
覆盖,如果
则这条边会被
覆盖。
例如被
覆盖:
或者被
覆盖:
代码
#include <bits/stdc++.h>
#define _for(i, a) for (register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for (register int i = (a), lennn = (b); i <= lennn; ++i)
#define mem0(a) memset(a, 0, sizeof(a))
using namespace std;
const int maxn = 200005;int n;
int deg[maxn];
vector<int> G[maxn];
vector<int> a;void init() { a.clear(); }void dfs(int u, int fa) {if (deg[u] == 1) a.push_back(u);for (int v : G[u]) {if (v != fa) {dfs(v, u);}}
}void sol() {init();_for(i, n - 1) {int u, v;scanf("%d%d", &u, &v);G[u].push_back(v);G[v].push_back(u);++deg[u];++deg[v];}dfs(1, -1);int l = a.size();printf("%d\n", (l + 1) / 2);if (l & 1) printf("%d %d\n", a[0], a[l / 2]);_for(i, l / 2) printf("%d %d\n", a[i], a[i + (l + 1) / 2]);
}int main() {while (cin >> n) {sol();}return 0;
}