定义:
树的重心也叫树的质心。对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点数最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小。
性质:
- 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
- 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
- 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
- 一棵树最多有两个重心,且相邻。
重心的求法
删除重心后最大连通块的结点数最小,那么就要对每个结点,以其为根,找出其所有子树的最大结点数,然后找出 子树最大结点数最小的那个结点,即是重心。
那么怎么一次DFS在O(N)的时间就找出重心呢?
随意选择一个根结点,进行DFS,对于 某个结点u ,每次向下遍历,可以得出 u向下遍历的各个子树的结点数 ,但是如果以u作为根结点话,还有 一颗向上遍历的子树结点数 没有考虑,但是可以发现 这棵向上遍历的子树的结点数= N - 向下遍历的各子树结点数之和 -1
具体实现:
int min_balance=INF; //删除重心后最大连通块的数量
int min_node; //重心
int dfs(int u) //dfs每次返回以u为根的子树的结点数量
{
vis[u]=true;
int sum=0; //向下遍历的各子树结点数之和
int max_subtree=0; //最大子树结点数
for(int i=head[u];i!=-1;i=e[i].next) //向下遍历
{
int v=e[i].v;
if(vis[v])
continue;
int t=dfs(