樹的重心,也叫樹的質心。即樹的一個點,以它爲根時所有子樹最大子樹最小。刪去重心後,生成的多棵樹儘可能平衡。
在樹的點分治中通常要用到。
性質
- 樹中所有點到某個點的距離和中,到重心的距離和是最短的。如果有兩個重心,它們的距離和相等。
- 把兩棵樹用一條邊相連,新的樹的重心在原來兩棵樹的重心的連線上。
- 一棵樹添加或刪除一個節點後,樹的重心最多隻移動一條邊的位置。
- 一棵樹最多有兩個重心,且相鄰。
求法
先任意取一個點作爲根,在這棵樹上求出每一個子樹的大小,對每個結點求它的各個子樹的最大大小,若 v 是 u 的子樹,那麼 。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;
}
資料來源:
百度百科