树形结构 —— 树与二叉树 —— 树的重心

【概述】

树的重心也叫树的质心,对于一棵具有 n 个结点的无根树,找到一个点,使得将树变为以该点为根的有根树时,最大子树的结点数最小

简单来说,就是给定一棵 n 个点的树,当删除某点 x 后,使得最大连通块最小,此时点 x 即为树的重心。

相关性质:

  1. 一棵树最多有两个重心,且这两个重心相邻
  2. 一棵树添加或删除一个节点时,树的重心最多只移动一条边的位置
  3. 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上
  4. 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样

树的重心同样可以用 dfs 来求,设 size[i] 表示以 i 为根的子树的总大小,mson 表示以 i 为根的最大子树的大小,然后利用 dfs 维护这两个数组即可

最后只需要求所有的 max(n-size[x], mson[x]) 的最小值即为以 x 为根时最大子树的大小,其中 n-size[x] 代表删去 x 及其子树后的连通块大小

【实现】

struct Edge {
    int to, val;
    int next;
    Edge() {}
    Edge(int to, int val, int next) : to(to), val(val), next(next) {}
} edge[N];
int n;
int head[N], tot;
int size[N], mson[N];
int core, minBalance = INF;
void addEdge(int from, int to, int val) {
    edge[++tot].to = to;
    edge[tot].val = val;
    edge[tot].next = head[from];
    head[from] = tot;
}
void dfs(int x, int father) {
    size[x] = 1;
    mson[x] = 0;
    for (int i = head[x]; i != -1; i = edge[i].next) {
        int y = edge[i].to;
        if (y == father)
            continue;
        dfs(y, x);
        size[x] += size[y];
        mson[x] = max(mson[x], size[y]);
    }
    mson[x] = max(n - size[x], mson[x]);
    if (mson[x] < minBalance) {
        core = x;
        minBalance = mson[x];
    }
}
int main() {
    scanf("%d", &n);
    memset(head, -1, sizeof(head));
    for (int i = 1; i <= n - 1; i++) {
        int x, y, val;
        scanf("%d%d%d", &x, &y, &val);
        addEdge(x, y, val);
        addEdge(y, x, val);
    }
    dfs(1, 0);
    printf("%d %d\n", core, minBalance);
    return 0;
}

 

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页