AT ARC156C Tree and LCS 题解
贪心考虑,要使得 \(x, P\) 最小,要么出现的共同节点最少,要么共同节点尽可能出现在某一(些)节点的异侧。从极端情况出发,如果 \(|x| = |P| = 1\),显然 \(\text{LCS} = 1\);如果 \(|x| = |P| = n\),所有点都出现过一次,不可能出现 \(\text{LCS} = 0\) 的情况,如果构造出 \(\text{LCS} = 1\),意味着在 \(x, P\) 中,除了一个相同的路径之外,其余的节点出现位置刚好镜像或者说相反。
构造方法如下:
- 任意选取两个叶子,将它们的权值交换
- 删掉两个叶子,重复这个过程
- 将最后留下的加入答案序列
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 5007;
int n;
int ind[N], ans[N];
std::vector<int> adj[N];
void bfs() {
std::queue<int> q;
for (int i = 1; i <= n; i++) {
if (ind[i] == 1)
q.push(i);
}
for (int i = 1; i <= (n / 2); i++) {
int u1 = q.front(); q.pop();
int u2 = q.front(); q.pop();
ans[u1] = u2; ans[u2] = u1;
for (auto v : adj[u1]) {
ind[v]--;
if (ind[v] == 1)
q.push(v);
}
for (auto v : adj[u2]) {
ind[v]--;
if (ind[v] == 1)
q.push(v);
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n;
for (int i = 1, u, v; i < n; i++) {
std::cin >> u >> v;
adj[u].push_back(v); ind[v]++;
adj[v].push_back(u); ind[u]++;
}
bfs();
for (int i = 1; i <= n; i++) {
if (ans[i])
std::cout << ans[i] << " ";
else
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}

浙公网安备 33010602011771号