luogu:https://www.luogu.com.cn/problem/P5536

\(n\) 座城市,\(n - 1\) 条道路,任意两座城市能通过若干条道路互通,将其中 \(k\) 座城市定义为核心城市。
\(k\) 座城市可以通过道路在不经过其它城市的情况下两两互通。
定义某个非核心城市与这 \(k\) 座城市的距离为这座城市到核心城市的最小距离,选择的核心城市要满足所有非核心城市的距离最大值最小。求出这个最小距离。

两遍 \(dfs\) 求直径

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5 + 10;
LL n, k, c, ans, d[N], pa[N], md[N], a[N];
vector <LL> g[N];
void dfs(LL u, LL fa){
	for (auto v : g[u]){
		if (v == fa) continue;
		d[v] = d[u] + 1;
		if (d[v] > d[c]) c = v;
		dfs(v, u);
	}
}
void findC(LL u, LL fa){
	for (auto v : g[u]){
		if (v == fa) continue;
		d[v] = d[u] + 1;
		pa[v] = u;
		if (d[v] > d[c]) c = v;
		findC(v, u);
	}
}
void calD(LL u, LL fa){
	md[u] = d[u];
	for (auto v : g[u]){
		if (v == fa) continue;
		d[v] = d[u] + 1;
		calD(v, u);
		md[u] = max(md[u], md[v]);
	}
}
int main(){
	cin >> n >> k;
	for (int i = 1; i < n; i ++ ){
		LL u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1, 0);
	d[c] = 0;
	findC(c, 0);
	LL t = d[c];
	for (int i = 1; i <= (t + 1) / 2; i ++ )
		c = pa[c];
	d[c] = 0;
	calD(c, 0);
	for (int i = 1; i <= n; i ++ )
		a[i] = md[i] - d[i] + 1;
	sort(a + 1, a + n + 1, [](LL a, LL b){
		return a > b;
	});
	for (int i = k + 1; i <= n; i ++ )
		ans = max(ans, a[i]);
	cout << ans << "\n";
	return 0;
}

\(dp\) 求直径

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e5 + 10;
LL n, k, c, dis, ans, d1[N], d2[N], d[N], pa[N], md[N], a[N];
vector <LL> g[N];
void dfs(LL u, LL fa){
	d1[u] = d2[u] = 0;  //注意距离的初始化
	for (auto v : g[u]){
		if (v == fa) continue;
		dfs(v, u);
		LL t = d1[v] + 1;
		if (t > d1[u])
			d2[u] = d1[u], d1[u] = t;
		else if (t > d2[u])
			d2[u] = t;
	}
	if (d1[u] + d2[u] > dis){
		dis = d1[u] + d2[u];	//找到最长的两条链之和 
		c = u;	//重心 
	}
}
void findC(LL u, LL fa){	//求出直径的路径 
	for (auto v : g[u]){
		if (v == fa) continue;
		d[v] = d[u] + 1;
		pa[v] = u;
		if (d[v] > d[c]) c = v;
		findC(v, u);
	}
}
void calD(LL u, LL fa){
	md[u] = d[u];
	for (auto v : g[u]){
		if (v == fa) continue;
		d[v] = d[u] + 1;
		calD(v, u);
		md[u] = max(md[u], md[v]);
	}
}
int main(){
	cin >> n >> k;
	for (int i = 1; i < n; i ++ ){
		LL u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1, 0);
	d[c] = 0;
	findC(c, 0);
	LL t = d[c];
	for (int i = 1; i <= (t + 1) / 2; i ++ )	//找到直径的中点 
		c = pa[c];
	d[c] = 0;
	calD(c, 0);
	for (int i = 1; i <= n; i ++ )
		a[i] = md[i] - d[i] + 1;
	sort(a + 1, a + n + 1, [](LL a, LL b){
		return a > b;
	});
	for (int i = k + 1; i <= n; i ++ )
		ans = max(ans, a[i]);
	cout << ans << "\n";
	return 0;
}
posted on 2022-05-09 14:21  Hamine  阅读(240)  评论(0编辑  收藏  举报