link
贪心考虑,要使得 \(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] << " ";elsestd::cout << i << " ";}std::cout << "\n";return 0;
}