讲解的方法是按照我自己的理解来的,有任何没有说清楚的地方欢迎提问。
-----------------------------------------------------------------------------------------------------
网上将有关的题目不少,但是详细讲这个算法的人不多。自己对着代码琢磨了一下,对这个算法讲一讲自己的理解。
首先,我们需要明白什么是树的中心。
先定义 |T| 为树T中结点的个数。
树的中心:将某个点V从树T中删除(连接这个点的边自然也删除了),会形成若干棵子树,其中结点个数最多的子树我们称其为最大子树M。如果该结点被删除使得 |M| < | 其他结点被删除得到的最大子树 |,则把V 称为树的中心。
那么,如何求树的中心呢,其实根据定义就行,挨个结点删除试试。而在实际操作中,我们不需要删除结点也能知道这棵树所有子树的大小,用删除这个词只是为了便于理解。
采用DFS来实现这个算法。
typedef vector<int>::iterator vc_i;
int center = -1;
vector<int> G[N];
int n;//树的结点总数
int sz[N]; //记录每个结点按其深搜方向所形成的树的节点个数。
int maxSub[N];//记录删除某个节点后所形成的所有子树中结点最多的子树的结点数量
void dfs(int cur, int pre)
{
sz[cur] = 1;
maxSub[cur] = 0;
for(vc_i i = G[cur].begin(); i != G[cur].end(); i++)
{
int v = *i;
if(v == pre) continue;
dfs(v, cur);
sz[cur] += sz[v];
maxSub[cur] = max(maxSub[cur], sz[v]);
}
maxSub[cur] = max(maxSub[cur], n - sz[cur]); //在整个过程中,我们搜索的子树漏掉了一棵,想想是哪棵? 看看continue那里就能想明白了
if(center == -1 || maxSub[cur] < maxSub[center])
center = cur;
}
但是这个方法求树的中心有局限,即你一定要先知道一共有多少个树结点。
而通过下面的性质④,可以不需要知道结点总数从而得到中心。
接下来说一些树的中心的性质,主要参考该链接:树的“重心”的一些性质及动态维护 。
①树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。
②把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。
③把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。
④树的中心一定在树的直径上。