【洛谷】P5536 题解(树的直径,贪心)
题目描述
X X X 国有 n n n 座城市, n − 1 n - 1 n−1 条长度为 1 1 1 的道路,每条道路连接两座城市,且任意两座城市都能通过若干条道路相互到达。显然,城市和道路形成了一棵树。
X X X 国国王决定将 k k k 座城市钦定为 X X X 国的核心城市,这 k k k 座城市需要满足以下两个条件:
- 这 k k k 座城市可以通过道路,在不经过其他城市的情况下两两相互到达。
- 定义某个非核心城市与这 k k k 座核心城市的距离为,这座城市与 k k k 座核心城市的距离的最小值。
那么所有非核心城市都有一个自己距离核心城市的距离 d i s i dis_{i} disi 。非核心城市到达核心城市的距离的最大值 d i s m a x = M a x ( d i s i ) dis_{max} =Max(dis_i) dismax=Max(disi) ,求出 d i s m a x dis_{max} dismax 的最小值。
输入格式
第一行:2个正整数 n n n , k k k 。
接下来 n − 1 n-1 n−1 行,每两行 2 2 2 个正整数 u u u . v v v ,表示第 u u u 座城市与第 v v v 座城市之间有一条长度为 1 1 1 的道路。
数据范围
- 1 ≤ k < n ≤ 1 0 5 1 \le k < n \le 10^5 1≤k<n≤105
- 1 ≤ u , v ≤ n , u ≠ v 1\le u,v \le n, u\neq v 1≤u,v≤n,u=v ,保证城市与道路形成一棵树。
输入输出样例
输入 #1
6 3
1 2
2 3
2 4
1 5
5 6
输出 #1
1
解题思路
简化问题
首先考虑如果只能建立 1 1 1 座核心城市,很容易得出,这个核心城市只能在 树的直径的中点 。
思路
-
由于 k k k 座核心城市必须 挨在一起 (条件1)。问题可以变成: 先在 树的直径的中点 建立核心城市,然后 延申 k − 1 k-1 k−1 座核心城市。
-
一座城市被立为核心城市的必要条件是:该城市在产生 d i s m a x dis_{max} dismax 的路径上
方法
- 先找出树的直径,根据树的直径找出树的中心
- 以 树的中心 跑一次 dfs ,维护 D e p [ x ] Dep[x] Dep[x] 。 ( D e p [ x ] Dep[x] Dep[x] 的值为: x x x 的子树节点到达 x x x 的距离的最大值 +1。意义是:如果 x x x 不是核心城市,那么其子树中的节点到达核心城市的距离的最大值)
- 给 D e p Dep Dep 数组降序排序,输出 D e p [ k + 1 ] Dep[k+1] Dep[k+1] 即为答案。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int dp[maxn];
int Dep[maxn];
int vis[maxn];
vector <int>p[maxn];
int n,k,a,b,Po1,Po_mid,Max_dep,d,ind;
void add_edge(int x,int y){
p[x].push_back(y);
p[y].push_back(x);
}
void Dp(int x,int fa){
int i,j;
for(i = 0; i < p[x].size(); i++){
j = p[x][i];
if(j == fa) continue;
Dp(j,x);
d = max (d, dp[x] + dp[j] + 1);
dp[x] = max(dp[x], dp[j] + 1);
}
}
void dfs1(int x,int fa,int dep){
if(dep > Max_dep){
Max_dep = dep;
Po1 = x;
}
int i,j;
for(i = 0; i < p[x].size(); i++){
j = p[x][i];
if(j == fa) continue;
dfs1(j,x,dep+1);
}
}
void dfs2(int x,int fa,int dep){
Dep[x] = dep;
if(Dep[x] == d){
for(int k = 1; k <= n; k++)
if(vis[k] && Dep[k] == d/2){
Po_mid = k;
break;
}
return;
}
int i,j;
for(i = 0; i < p[x].size(); i++){
j = p[x][i];
if(j == fa) continue;
vis[j] = 1;
dfs2 (j,x,dep+1);
vis[j] = 0;
}
}
void dfs3(int x,int fa,int dep){
Dep[x] = 1;
int i,j;
for(i = 0; i < p[x].size(); i++){
j = p[x][i];
if(j == fa) continue;
dfs3 (j,x,dep+1);
Dep[x] = max(Dep[x],Dep[j] + 1) ;
}
}
bool cmp(int x,int y){return x > y;}
int main(){
//freopen("P5536.in","r",stdin);
//freopen("P5536.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i = 1; i < n; i++){
scanf("%d%d",&a,&b);
add_edge(a,b);
}
Dp(1,0);
dfs1(1,0,0);
dfs2(Po1,0,0);
dfs3(Po_mid,0,0);
sort(Dep+1,Dep+1+n,cmp);
printf("%d",Dep[k+1]);
return 0;
}