zoukankan      html  css  js  c++  java
  • 【应用】树上问题-树的重心

    树的重心是什么?

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

    该树以根为分界,分为若干个子树,设其中最大子树具有的节点数为 (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;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    Windows打开文件后提示,文件或目录损坏无法读取。
    windows10 提示内存不足
    配置Redis集群为开机自启动
    Hbase的rowkey设计
    Hbase表类型的设计
    mycat的下载和安装
    mycat简介
    mysql|tomcat|nginx|redis在docker中的部署
    docker的备份和迁移
    Redis Cluster集群详介绍和伪集群搭建
  • 原文地址:https://www.cnblogs.com/RioTian/p/14306937.html
Copyright © 2011-2022 走看看