题意:给定一棵n个节点的树,每条边的长度为1,钦定k个节点为核心节点,这k个节点要满足两个条件:
1.这k座城市可以通过边,在不经过其他节点的情况下两两相互到达.
2.定义某个非核心节点与这k个核心节点的距离为这个节点与k个核心节点的距离的最小值,那么所有非核心节点中,与核心节点的距离最大的节点,其与核心节点的距离最小.你需要求出这个最小值.
因为我是通过搜索标签搜到这道题的,所以一开始就往"树的直径"上面想了.这k个节点必定是树的直径上的一段,且k个节点的中点就是树的直径的中点.
所以我们先两次(DFS)找出树的直径,第二次(DFS)时通过记录路径(pre),找到树的直径的中点.然后以这个中点为根再一次(DFS),处理出(dis[i])表示根节点到节点i的距离,(dist[i])表示以节点i为根的子树中,从i出发能够到达的最远距离.
然后我们把所有节点按照(dist[i]-dis[i])从大到小排序,前k个就是所谓核心节点了.
因为各种各样的原因,这道题我压行了,因为我发现不压行的话代码又长又丑,压行的话只是丑一点...
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define ll long long
using namespace std;
inline int read(){
int x=0,o=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')o=-1,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*o;
}
const int N=1e5+5;
int dis[N],pre[N],a[N],c[N],dist[N],bj[N];
int tot,head[N],nxt[N<<1],to[N<<1];
struct ppx{int val,id;}b[N];
inline bool cmp(ppx x,ppx y){return x.val>y.val;}
inline void add(int a,int b){nxt[++tot]=head[a];head[a]=tot;to[tot]=b;}
inline void dfs1(int u,int fa){
for(int i=head[u];i;i=nxt[i]){
int v=to[i];if(v==fa)continue;
dis[v]=dis[u]+1;dfs1(v,u);
}
}
inline void dfs2(int u,int fa){
for(int i=head[u];i;i=nxt[i]){
int v=to[i];if(v==fa)continue;
dis[v]=dis[u]+1;pre[v]=u;dfs2(v,u);
}
}
inline void dfs3(int u,int fa){
dist[u]=dis[u];
for(int i=head[u];i;i=nxt[i]){
int v=to[i];if(v==fa)continue;
dis[v]=dis[u]+1;dfs3(v,u);
dist[u]=max(dist[u],dist[v]);
}
}
int main(){
int n=read(),k=read();
for(int i=1;i<n;++i){int a=read(),b=read();add(a,b);add(b,a);}//存图
dfs1(1,0);int maxn=0,pos1,pos2;//第一次以任意一个节点为根dfs
for(int i=1;i<=n;++i)if(dis[i]>maxn){maxn=dis[i];pos1=i;}//找到距离最远的那个点pos1
memset(dis,0,sizeof(dis));dfs2(pos1,0);maxn=0;//以pos1为根第二次dfs
for(int i=1;i<=n;++i)if(dis[i]>maxn){maxn=dis[i];pos2=i;}//找到距离最远的那个节点pos2,此时pos1-pos2就是树的直径
int tot=0;while(pos2!=pos1){a[++tot]=pos2;pos2=pre[pos2];}//递归存储直径上的所有节点
a[++tot]=pos1;reverse(a+1,a+tot+1);
int root=a[(tot+1)/2];memset(dis,0,sizeof(dis));dfs3(root,0);//找到中点,以其为根dfs
for(int i=1;i<=n;++i){
b[i].val=dist[i]-dis[i];
b[i].id=i;c[i]=b[i].val;
}
sort(b+1,b+n+1,cmp);
for(int i=1;i<=k;++i)bj[b[i].id]=1;//选出k个核心节点
int ans=0;
for(int i=1;i<=n;++i)
if(!bj[i])ans=max(c[i]+1,ans);//不是核心节点,就计算贡献
printf("%d
",ans);
return 0;
}