题目链接
题意
输入一个n(n≤100000)个结点的树,添加尽量少的边,使得任意删除一条边之后图仍然连通。如下图所示,最优方案用虚线表示。
分析
首先统计叶结点数c,即可知道答案是
⌈
c
2
⌉
\lceil\frac{c}2\rceil
⌈2c⌉,然后将叶结点两两配对连边即可,不过注意要优先将不在同一个枝杈的两叶结点配对(看下图就能理解)。
可以遍历每个叶结点找出它连接到的枝杈点,这样就统计出了每个枝杈点有哪些叶结点,然后对每一个枝杈点先拿出一个叶结点做配对,其他叶结点存着等后面再任意配对即可。
还可以任取一个非叶结点作为根对树做dfs遍历,遍历过程遇到叶结点就存起来,将存起来的叶结点看成循环队列则可以发现属于同一个枝杈点的叶结点处在队列连续的一段。这时候就很容易对叶结点做配对了:将第
i
i
i个叶结点和第
i
+
⌊
c
2
⌋
i+\lfloor\frac{c}2\rfloor
i+⌊2c⌋个叶结点配对连边。
AC 代码
本题UVa数据出问题了,提交必WA,Codeforces上对应的题目是GYM 100085K,可提交(先加上freopen,输入自 kingdom.in ,输出到 kingdom.out)。
按枝杈点点对叶结点做分类的方法
#include <iostream>
#include <vector>
using namespace std;
#define N 100100
int q[N], n; vector<int> g[N], gg[N];
void solve() {
int c = 0;
for (int i=1; i<=n; ++i) g[i].clear(), gg[i].clear();
for (int i=1, u, v; i<n; ++i) cin >> u >> v, g[u].push_back(v), g[v].push_back(u);
for (int i=1; i<=n; ++i) if (g[i].size() == 1) {
int u = g[i][0], p = i, v; ++c;
while (g[u].size() == 2) v = u, u = g[u][0]+g[u][1]-p, p = v;
gg[u].push_back(i);
}
cout << (c+1)/2 << endl;
int head = 0, tail = 0;
for (int i=1; i<=n; ++i) {
int s = gg[i].size();
if (s>1 && head<tail) cout << q[head++] << ' ' << gg[i].back() << endl, --s;
for (int j=0; j<s; ++j) q[tail++] = gg[i][j];
}
for (int i=head+1; i<tail; i+=2) cout << q[i-1] << ' ' << q[i] << endl;
if (c&1) cout << q[0] << ' ' << q[tail-1] << endl;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
while (cin >> n) solve();
return 0;
}
dfs法
#include <iostream>
#include <vector>
using namespace std;
#define N 100100
int q[N], n, c; vector<int> g[N];
void dfs(int u, int p = -1) {
if (g[u].size() == 1) q[c++] = u;
for (int i=g[u].size()-1, v; i>=0; --i) if ((v = g[u][i]) != p) dfs(v, u);
}
void solve() {
c = 0;
for (int i=1; i<=n; ++i) g[i].clear();
for (int i=1, u, v; i<n; ++i) cin >> u >> v, g[u].push_back(v), g[v].push_back(u);
for (int i=1; i<=n; ++i) if (g[i].size() > 1) {
dfs(i); break;
}
cout << (c+1)/2 << endl;
for (int i=0, m=c>>1; i<m; ++i) cout << q[i] << ' ' << q[i+m] << endl;
if (c&1) cout << q[0] << ' ' << q[c-1] << endl;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
while (cin >> n) solve();
return 0;
}