X 国有 n 座城市,n−1 条长度为 1 的道路,每条道路连接两座城市,且任意两座城市都能通过若干条道路相互到达,显然,城市和道路形成了一棵树。
X 国国王决定将 k 座城市钦定为 X 国的核心城市,这 k 座城市需满足以下两个条件:
这 k 座城市可以通过道路,在不经过其他城市的情况下两两相互到达。
定义某个非核心城市与这 k 座核心城市的距离为,这座城市与 k 座核心城市的距离的最小值。那么所有非核心城市中,与核心城市的距离最大的城市,其与核心城市的距离最小。你需要求出这个最小值。
题解:
先找出树直径的中心root,以它为根节点,然后dfs去二分深度找答案
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; int head[maxn], tot, father[maxn]; struct Edge { int u, v, next; } edge[maxn]; void init() { memset(head, -1, sizeof(head)); tot = 1; } void add(int u, int v) { edge[++tot].u = u; edge[tot].v = v; edge[tot].next = head[u]; head[u] = tot; } int root, dp[maxn], depth[maxn], cnt[maxn]; int mx; void dfs(int u, int fa) { int mx1 = 0, mx2 = 0; father[u] = fa; dp[u] = 1; for (int i = head[u]; i != -1; i = edge[i].next) { int to = edge[i].v; if (to == fa) continue; dfs(to, u); dp[u] = max(dp[u], dp[to] + 1); if (dp[to] > mx1) { mx2 = mx1; mx1 = dp[to]; } else if (dp[to] > mx2) { mx2 = dp[to]; } } if (mx1 + mx2 > mx) { root = u; mx = mx1 + mx2; } } void getRoot(int u, int fa) { root = u; for (int i = head[u]; i != -1; i = edge[i].next) { int to = edge[i].v; if (to == fa) continue; if (dp[to] > mx / 2) { getRoot(to, u); } } } void init_dp(int u, int fa) { cnt[u] = 1; depth[u] = 1; for (int i = head[u]; i != -1; i = edge[i].next) { int to = edge[i].v; if (to == fa) continue; init_dp(to, u); depth[u] = max(depth[u], depth[to] + 1); cnt[u] += cnt[to]; } } int n, k, u, v; int check(int u, int fa, int x) { if (depth[u] <= x) return cnt[u]; int res = 0; for (int i = head[u]; i != -1; i = edge[i].next) { int to = edge[i].v; if (to == fa) continue; res += check(to, u, x); } return res; } int main() { //freopen("in.in", "r", stdin); init(); cin >> n >> k; for (int i = 1; i <= n - 1; i++) { cin >> u >> v; add(u, v); add(v, u); } dfs(1, 0); getRoot(root, father[root]); init_dp(root, 0); int l = 1, r = depth[root]; int ans = 1; while (l <= r) { int mid = (l + r) / 2; if (n - check(root, 0, mid) <= k) { ans = mid; r = mid - 1; } else { l = mid + 1; } } cout << ans << endl; return 0; }