树的重心
使用背景: 对一颗无根树,求重心.(当然,对一棵树,究竟是有根还是无根,完全自己说了算),
感性定义: 作为根时,能使各子树节点数目"均衡"的节点。
明确定义: 设 f ( x ) f(x) f(x)表示节点 x x x为根时,所有的子树节点个数中的最大值。 f ( x ) f(x) f(x)最小的节点即这颗无根树的重心。
性质:
- 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。
- 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。
- 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。
- 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。
求法: 在 DFS 中计算每颗子树的大小,记录“向下”的子树的最大大小,利用总点数 - 当前子树(这里的子树指有根树的子树)的大小得到“向上”的子树的大小,得出当前节点的 f ( x ) f(x) f(x),根据定义,更新重心。
vector<int> tree[maxn];
int rt, sbsz = INT_MAX;
int n;
void getCentroid(int u, int f, int &sz)
{
sz = 1;
int maxsubtree = 0;
for (auto v : tree[u])
{
if (v == f)continue;
int temp;
getCentroid(v, u, temp);
sz += temp;
if (temp > maxsubtree)maxsubtree = temp;
}
maxsubtree = max(maxsubtree, n - sz);
if (maxsubtree < sbsz)rt = u, sbsz = maxsubtree;
}
复杂度分析: 只使用了一遍dfs,复杂度为 O ( v + e ) O(v + e) O(v+e)
拓展: 感性定义中,提到了“均衡”, 这里的均衡是指子节点数目的均衡,那么,是否可以用类似的dfs求叶子节点数目的均衡?求边权总和的均衡?答案是可以的,只需要改变sz的求法就可以了。