树的重心,也叫树的质心。即树的一个点,以它为根时所有子树最大子树最小。删去重心后,生成的多棵树尽可能平衡。
在树的点分治中通常要用到。
性质
- 树中所有点到某个点的距离和中,到重心的距离和是最短的。如果有两个重心,它们的距离和相等。
- 把两棵树用一条边相连,新的树的重心在原来两棵树的重心的连线上。
- 一棵树添加或删除一个节点后,树的重心最多只移动一条边的位置。
- 一棵树最多有两个重心,且相邻。
求法
先任意取一个点作为根,在这棵树上求出每一个子树的大小,对每个结点求它的各个子树的最大大小,若 v 是 u 的子树,那么 m a x s i z e u = m a x { m a x ( s i z e v ) , n − s i z e u } maxsize_u=max\{max(size_v),n-size_u\} maxsizeu=max{max(sizev),n−sizeu}。dfs 一遍 O(n) 求出。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int n;
//Edge
struct Edge
{
int to, next;
}e[N];
int hn, h[N];
void add(int u, int v)
{
e[++hn].to=v; e[hn].next=h[u];
h[u]=hn;
}
//weight
int sz[N], pos, minz;
void dfs(int u, int fa)
{
sz[u]=1;
int maxz=0;
for(int p=h[u]; p; p=e[p].next)
{
int v=e[p].to;
if(v==fa) continue;
dfs(v,u);
sz[u]+=sz[v];
maxz=max(maxz,sz[v]);
}
maxz=max(maxz,n-sz[u]);
if(maxz<minz)
{
pos=u;
minz=maxz;
}
}
int main()
{
scanf("%d", &n);
for(int i=1, u, v; i<n; ++i)
{
scanf("%d%d", &u, &v);
add(u,v); add(v,u);
}
minz=n;
dfs(1,0);
printf("%d", pos);
return 0;
}
资料来源:
百度百科