树的重心

发布时间 2023-08-06 10:29:16作者: o-Sakurajimamai-o
树的重心:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。使得以该节点为根的子树中,最大子树高度最小的节点
 
//会议
//https://www.luogu.com.cn/problem/P1395

// f数组:f数组用于记录以每个节点为根的子树中的最大深度(高度)。对于每个节点u,f[u]表示以u为根的子树的最大深度。

// g数组:g数组用于记录以每个节点为根的子树中,u的子节点(不包括u本身)到其他叶子节点的最大距离(即最长路径)。
// 对于每个节点u,g[u]表示以u为根的子树中,u的子节点到其他叶子节点的最大距离。

//树的重心:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
//树的重心是使得以该节点为根的子树中,最大子树高度最小的节点
//根据重心定义,
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,res,f[N],g[N],num,ans=2e9;
int e[N],ne[N],h[N],idx;
bool vis[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u)
{
    vis[u]=true;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(!vis[j]){
            dfs(j);
            g[u]+=g[j]+1;
            f[u]=max(f[u],g[j]+1);
        }
    }
    f[u]=max(f[u],n-g[u]-1);
    vis[u]=false;
}
int main()
{
    cin>>n;
    memset(h, -1, sizeof h);
    for(int i=0;i<n-1;i++){
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs(1);//以任意一个节点开始,寻找树的重心
    cout<<f[1]<<endl;
    for(int i=1;i<=n;i++)
        if(ans>f[i]) num=i,ans=f[i];
    cout<<num<<" ";
    memset(g,0,sizeof(g));
    dfs(num);//重置,搜索重心
    for(int i=1;i<=n;i++) res+=g[i];
    cout<<res<<endl;
    return 0;
}