村子(最大化)
肯定是越远越好哦~
那么若我们考虑一个边(edge),最多能有多少个经过?
让边的两端为a,b。最大贡献肯定是2*min(sz[a],sz[b]),sz表示子树的大小。
那怎么拿到最大贡献值呢?中心点啊啊啊!!!!!!。
若我们把中心点放为root, 那么我们可以保证最大值哦(๐॔˃̶ᗜ˂̶๐॓)。若我们在中心点开始,把左边移去右边,右边相似。
我们建村民的位置时可以用到dfs的顺序(走完左边的点先再走右边),我们利用中心点的特征:左右都有n/2的点。 所以我们可以直接放对立的。
具体代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
ios_base::sync_with_stdio(0); cin.tie(0);
int n; cin >> n;
vector<vector<int>> g(n + 5);
for (int i = 0; i < n - 1; i++) {
int u, v; cin >> u >> v;
u--; v--;
g[u].push_back(v); g[v].push_back(u);
}
vector<int> sz(n + 5), a;
int sum = 0;
function<void(int, int)> dfs = [&](int u, int f) {
sz[u] = 1; a.push_back(u);
for (auto& v : g[u]) {
if (v == f) continue;
dfs(v, u);
sz[u] += sz[v];
}
sum += 2 * min(sz[u], n - sz[u]);
};
function<int(int, int)>find_centroid = [&](int u, int f) {
for (auto& v : g[u]) {
if (v == f) continue;
if (2 * sz[v] > n) return find_centroid(v, u);
}
return u;
};
dfs(0, -1);
int root = find_centroid(0, -1);
a.clear(); sum = 0;
dfs(root, -1);
vector<int> ans(n);
for (int i = 0; i < n; i++) {
ans[a[i]] = a[(i + n / 2) % n];//左右最多n/2所以肯定不会在同一个子树
}
cout << sum << '\n';
for (int i = 0; i < n; i++) cout << ans[i] + 1 << ' ';
cout << '\n';
}
浙公网安备 33010602011771号