P5536 【XR-3】核心城市(直径)

题目描述

X 国有 n 座城市,n − 1 条长度为 1 的道路,每条道路连接两座城市,且任意两座城市都能通过若干条道路相互到达,显然,城市和道路形成了一棵树。

X 国国王决定将 k 座城市钦定为 X 国的核心城市,这 k 座城市需满足以下两个条件:

  1. 这 k 座城市可以通过道路,在不经过其他城市的情况下两两相互到达。
  2. 定义某个非核心城市与这 k 座核心城市的距离为,这座城市与 k 座核心城市的距离的最小值。那么所有非核心城市中,与核心城市的距离最大的城市,其与核心城市的距离最小。你需要求出这个最小值。

输入格式

第一行 2个正整数 n,k。

接下来 n - 行,每行 2 个正整数 u,v表示第 u座城市与第 v 座城市之间有一条长度为 1 的道路。

输出格式

一行一个整数,表示答案。

输入输出样例

输入
6 3
1 2
2 3
2 4
1 5
5 6
输出
1

说明/提示

【样例说明】

钦定 1,2,5 这 3座城市为核心城市,这样 3,4,6 另外 3座非核心城市与核心城市的距离均为 1,因此答案为 1。

数据范围:

  • 1<=k<n<=105
  • 1<=u,v<=n,u≠v,保证城市与道路形成一棵树。

思路

  1. 显然,当k为1时,核心城市就是直径的中点,设为x。
  2. 因为核心城市是挨在一起的,所以我们可以遍历x能到达的点,并从中选取一个可以使答案变得最小的点作为下一个核心城市,直到选够k座核心城市为止。

过程

  1. 两遍dfs求直径并且记下路径。
  2. 取直径的中点作为第一座核心城市 ,并作为根节点,记为x。
  3. 以x为根节点进行遍历,计算出每个点的深度d以及每个点能到达的最大深度maxd。
  4. 以x为根节点进行遍历,从核心城市能到达的点中选maxd[v]-d[v]最大的点作为下一个核心城市,直到选够为止。

代码

#include<cstdio>
#include<algorithm>
#define ri register int
using namespace std;
const int maxn=1e5+7;
struct E{
	int v,nxt;
}e[maxn<<1];
int head[maxn];
int f[maxn];
int d[maxn],maxd[maxn],dis[maxn];
int cnt,n,k,tmp,r,ans;
bool cmp(int x,int y){ return x>y;}
inline int read(){//快读 
	int x=0;
	char c=getchar();
	while(c>'9'||c<'0') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x;
}
inline void add(int u,int v){//建边 
	cnt++;
	e[cnt].v=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void dfs(int u,int fa,int kk){//第一、二遍dfs找直径 
	if(d[u]>tmp) tmp=d[u],r=u;
	for(ri i=head[u];i;i=e[i].nxt) 
	{
		int v=e[i].v;
		if(v==fa) continue;
		if(kk) f[v]=u;
		d[v]=d[u]+1;
		dfs(v,u,kk);
	}
}
void dfs1(int u,int fa){//求d和maxd 
	maxd[u]=d[u];
	for(ri i=head[u];i;i=e[i].nxt)
	{
		int v=e[i].v;
		if(v==fa) continue;
		d[v]=d[u]+1;
		dfs1(v,u);
		if(maxd[v]>maxd[u]) maxd[u]=maxd[v];
	}
}
int main(){
	n=read(),k=read();
	for(ri i=1;i<n;++i)
	{
		int u=read(),v=read();
		add(u,v),add(v,u);
	}
	dfs(1,0,0);
	d[r]=tmp=0;
	dfs(r,0,1);
	int x=r;
	for(ri i=1;i<=(d[x]+1)>>1;++i) r=f[r];
	d[r]=0;
	dfs1(r,0);
	for(ri i=1;i<=n;++i) dis[i]=maxd[i]-d[i];
	sort(dis+1,dis+n+1,cmp);
	printf("%d",dis[k+1]+1);//显然dis[k+1]+1是最大的
	return 0;
}
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Robin_w2321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值