首页 > 其他 > 详细

树的重心

时间:2019-11-07 01:25:19      阅读:105      评论:0      收藏:0      [点我收藏+]

定义来源https://oi-wiki.org/graph/tree-misc/

树的重心

定义

以树的重心为根时,所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心。

删去重心后,生成的多棵树尽可能平衡。

性质

树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。

把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两个树的重心的路径上。

在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

求法:利用第二个性质

struct CenterTree {
  int n;
  int ans;
  int siz;
  int son[maxn];
  void dfs(int u, int pa) {
    son[u] = 1;
    int res = 0;
    for (int i = head[u]; ~i; i = edges[i].next) {
      int v = edges[i].to;
      if (v == pa) continue;
      dfs(v, u);
      son[u] += son[v];
      res = max(res, son[v]);
    }
    res = max(res, n - son[u]);
    if (res < siz) {
      ans = u;
      siz = res;
    }
  }
  int getCenter(int x) {
    ans = 0;
    siz = INF;
    dfs(x, -1);
    return ans;
  }
}

 

另一道有意思的题http://codeforces.com/contest/686/problem/D

解法: 利用重心的性质,某一个点的重心在最大(节点最多)的那个子树上,并且在在这个节点到最大子树的重心之间,重心满足num[x] * 2 > = num[u],x为重心,u为要求重心的节点,num[]代表这个节点的子树的节点个数。

因为只要找到num[x] * 2 > = num[u] 的x就停止,证明在x儿子的时候还是满足(num[son[x]] * 2 < num[u] )的, 当x被erase后 剩下的最大子树的节点绝对不会超过num[u]/2, 所以x就是重心;

某人代码

void dfs(int u)
{
    num[u] = 1;
    int pos,t = 0;
    for(int i = 0; i < g[u].size(); i ++)
    {
        int v = g[u][i];
        dfs(v);
        if(num[v] > t)t = num[v],pos = v;
        num[u] += num[v];
    }
    if(num[u] == 1 || num[u] == 2)
    {
        ans[u] = u;
        return;
    }
    int x= ans[pos];
    while(num[x] * 2 < num[u])
        x = fa[x];
    ans[u] = x;
}

 

树的重心

原文:https://www.cnblogs.com/ertuan/p/11809694.html

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