首页 > 其他 > 详细

【应用】树上问题-树的重心

时间:2021-01-21 12:12:57      阅读:34      评论:0      收藏:0      [点我收藏+]

树的重心是什么?

对于一棵无根树,设其中的一个节点作为根,则可以形成一棵有根树。

该树以根为分界,分为若干个子树,设其中最大子树具有的节点数为 \(x\)

所有节点里, \(x\) 值最小的节点就是该树的重心,也叫质心。

例如上图这棵树,以1为根时,三个子树的大小分别为3、3、2,其中最大的为3。

1就是这棵树的重心,因为以其他节点为根时,最大子树的大小都会超过3。

比如假设以3为根,则其会有两个子树,分别为{7,8}和{1,2,4,5,6,9},其中最大的子树大小为6。

技术分享图片

重心的性质

重心相当于树的平衡点,其尽量均匀地将树分割成了若干部分。

在树分治以及树同构中,重心都具有相当重要的地位。

重心具有几个比较重要的性质:

①一棵树最少有一个重心,最多有两个重心,若有两个重心,则他们相邻(即连有直接边)。

②树上所有点到某个点的距离和里,到重心的距离和最小;若有两个重心,则其距离和相同。

③若以重心为根,则所有子树的大小都不超过整棵树的一半。否则可以通过平移使得最大子树的大小缩小至整树的一半,剩下子树的大小最大为 \(n / 2 - 1\) 。此时新平移到的点才是真正的重心。

④在一棵树上添加或删除一个叶子节点,其重心最多平移一条边的距离。

⑤两棵树通过连一条边组合成新树,则新树重心在原来两棵树的重心的连线上。

如何求解重心?

按其定义来求即可。

我们任选一个节点作为根,然后跑DFS,在过程中记录每个节点各个子树的大小。对于每个节点,其还存在一个上方的子树(即从假设根到当前节点),其大小为总节点数减去当前节点的总子树大小。

然后就能得到每个节点最大子树的节点数,取其中最小值即可。

整个算法只需要遍历一遍树,时间复杂度为 \(O(n)\)

代码实现:

int siz[N], wgt[N];    // size and weight, weight mean max sontree
int n, mi = inf, ans;  // mi=min max size, ans=重心
void dfs(int now, int fa) {
    siz[now] = 1;
    wgt[now] = 0;
    for (int i = 0; i < e[now].size(); i++) {
        int to = e[now][i];
        if (to == fa)
            continue;
        dfs(to, now);
        siz[now] += siz[to];
        wgt[now] = max(wgt[now], siz[to]);
    }
    wgt[now] = max(wgt[now], n - siz[now]);
    if (wgt[now] < mi)
        mi = wgt[now], ans = now;
}

【应用】树上问题-树的重心

原文:https://www.cnblogs.com/RioTian/p/14306937.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!