【算法】樹的重心

樹的重心,也叫樹的質心。即樹的一個點,以它爲根時所有子樹最大子樹最小。刪去重心後,生成的多棵樹儘可能平衡。

在樹的點分治中通常要用到。

性質

  1. 樹中所有點到某個點的距離和中,到重心的距離和是最短的。如果有兩個重心,它們的距離和相等。
  2. 把兩棵樹用一條邊相連,新的樹的重心在原來兩棵樹的重心的連線上。
  3. 一棵樹添加或刪除一個節點後,樹的重心最多隻移動一條邊的位置。
  4. 一棵樹最多有兩個重心,且相鄰。

求法

先任意取一個點作爲根,在這棵樹上求出每一個子樹的大小,對每個結點求它的各個子樹的最大大小,若 v 是 u 的子樹,那麼 maxsizeu=max{max(sizev),nsizeu}maxsize_u=max\{max(size_v),n-size_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;
}

資料來源:
百度百科

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章