P5536 XR-3核心城市(树的直径)

Posted CCSU_Cola

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5536 XR-3核心城市(树的直径)相关的知识,希望对你有一定的参考价值。

题目链接

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

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

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

题意:在树上找k个点作为核心城市(k个城市必须两两互相连通),使得树上到核心城市最远的点到核心城市的距离最短。

思路:若k等于1,那么一定是选择树的直径的中心点,因为k个点互相连通,那么其余的k-1个点必须以树直径的中心点进行进行延伸,于是我们需要以树的直径的中心点作为根节点进行一次dfs,求出它自己距离根节点的距离,以及该点能到的距离根节点最远的点的深度,也就是能到的最深的点的深度。然后以能到达的最深的点的深度减去自身的深度即可得到若不以该节点作为核心城市则其所有子节点中最远到达核心城市的点的距离。只需要选出最大的k-1个,第k大的即为选取之后的答案。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100010;
struct tt{
    int x,to;
};
tt e[maxn<<1];
int n,k,idx,h[maxn];
void add(int a,int b){
    e[idx].x=b,e[idx].to=h[a],h[a]=idx++;
}
int ans=-1,pos;
void dfs(int x,int fa,int step){
    if(step>ans){
        pos=x;
        ans=step;
    }
    for(int i=h[x];i!=-1;i=e[i].to){
        int j=e[i].x;
        if(j==fa)continue;
        dfs(j,x,step+1);
    }
}
int depth[maxn],f[maxn],mx_depth[maxn];
void dfs_dep(int x,int fa,int step){
    depth[x]=step;
    for(int i=h[x];i!=-1;i=e[i].to){
        int j=e[i].x;
        if(j==fa)continue;
        f[j]=x;
        dfs_dep(j,x,step+1);
    }
}
void dfss(int x,int fa){
    mx_depth[x]=depth[x];
    for(int i=h[x];i!=-1;i=e[i].to){
        int j=e[i].x;
        if(j==fa)continue;
        depth[j]=depth[x]+1;
        dfss(j,x);
        mx_depth[x]=max(mx_depth[x],mx_depth[j]);
    }
}
int an[maxn];
bool cmp(int a,int b){
    return a>b;
}
int main(){
    scanf("%d%d",&n,&k);
    int a,b;
    memset(h,-1,sizeof h);
    for(int i=1;i<n;i++){
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    dfs(1,-1,0);
    int ff=pos;
    ans=-1;
    dfs(ff,-1,0);
    dfs_dep(ff,-1,0);
    int kk=pos;
    for(int i=1;i<=depth[pos]/2;i++){
        kk=f[kk];
    }
    memset(depth,0,sizeof depth);
    dfss(kk,-1);
    for(int i=1;i<=n;i++){
        an[i]=mx_depth[i]-depth[i];//得到所有点能到的最大深度-自己的深度
    }
    sort(an+1,an+1+n,cmp);//排序后取第k大的值
    printf("%d\\n",an[k+1]+1);
}

以上是关于P5536 XR-3核心城市(树的直径)的主要内容,如果未能解决你的问题,请参考以下文章

解题报告:luogu P5536 XR-3核心城市

[TJOI2017]城市 树的直径+暴力+优化

[TJOI2017]城市(树的直径)

大臣的旅费---树的直径(dfs)

luogu3761 [TJOI2017]城市

51 nod 1427 文明 (并查集 + 树的直径)