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


    树的重心是什么?

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

    该树以根为分界,分为若干个子树,设其中最大子树具有的节点数为 (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
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    webpack.DefinePlugin
    webpack-dev-server配置指南(使用webpack3.0)
    Eclipse配色方案插件
    解决Sublime Text 3中文显示乱码问题(转)
    Java连接SqlServer2008数据库
    [转]java中判断字符串是否为数字的三种方法
    VS2008 SP1 安装卡在 VS90sp1-KB945140-X86-CHS的解决方法
    Python获取桌面路径
    关于fdisk命令
    socket 错误之:OSError: [WinError 10057] 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。
  • 原文地址:https://www.cnblogs.com/RioTian/p/14306937.html
Copyright © 2020-2023  润新知