树的重心:概念、性质与算法详解

1. 什么是树的重心?

树的重心(Centroid of a Tree)是树形结构中的一个重要概念。对于一棵有 n 个节点的无根树,树的重心是指树中这样一个节点:如果以该节点为根,将树转换为有根树,那么所有子树中节点数最多的那个子树的节点数最小。

更形式化地定义:设树 T 有 n 个节点,对于任意节点 u,定义 size(u) 为以 u 为根的子树大小(节点数)。令 f(u) = max{size(v) | v 是 u 的子节点},则树的重心是使得 f(u) 最小的节点 u。

2. 重心的性质

树的重心具有以下几个重要性质:

  • 存在性:每棵树至少有一个重心,最多有两个重心。
  • 平衡性:以重心为根时,所有子树的大小都不超过 n/2。
  • 唯一性条件:当 n 为奇数时,树有且仅有一个重心;当 n 为偶数时,可能有一个或两个重心。
  • 递归性质:如果树有两个重心,那么这两个重心一定是相邻的。
  • 最优性:在树分治算法中,以重心为分割点可以保证递归深度为 O(log n)。

3. 寻找重心的算法

寻找树的重心可以使用一次 DFS(深度优先搜索)完成,时间复杂度为 O(n)。

算法步骤

  1. 任选一个节点作为根,进行 DFS。
  2. 对于每个节点 u,计算以 u 为根的子树大小 sizeu
  3. 同时计算 f(u) = max(n - sizeu, max{sizev | v 是 u 的子节点})。
  4. 找到所有节点中 f(u) 最小的节点,即为重心。

4. 代码实现(C++)

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int MAXN = 100005;
vector<int> graph[MAXN];
int size[MAXN], f[MAXN];
int n, centroid1 = -1, centroid2 = -1;

void dfs(int u, int parent) {
    size[u] = 1;
    int max_subtree = 0;
    
    for (int v : graph[u]) {
        if (v == parent) continue;
        dfs(v, u);
        size[u] += size[v];
        max_subtree = max(max_subtree, size[v]);
    }
    
    max_subtree = max(max_subtree, n - size[u]);
    f[u] = max_subtree;
}

int main() {
    cin >> n;
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        graph[u].push_back(v);
        graph[v].push_back(u);
    }
    
    dfs(1, 0);
    
    int min_f = *min_element(f + 1, f + n + 1);
    for (int i = 1; i <= n; i++) {
        if (f[i] == min_f) {
            if (centroid1 == -1) centroid1 = i;
            else centroid2 = i;
        }
    }
    
    cout << "重心: " << centroid1;
    if (centroid2 != -1) cout << " 和 " << centroid2;
    cout << endl;
    
    return 0;
}

5. 应用场景

树的重心在算法竞赛和实际应用中有着广泛用途:

  • 树分治:点分治算法的核心就是每次选择重心作为分治点。
  • 树的直径:重心与树的直径有密切联系,可以通过重心快速计算直径。
  • 网络设计:在树形网络中,重心可以作为最优的服务器放置位置。
  • 平衡分割:需要将树平衡分割时,重心是最佳分割点。

6. 例题解析

例题:给定一棵 n 个节点的树,求所有可能的重心。

分析:直接使用上述算法即可。注意当 n 为偶数时,可能存在两个重心,需要全部输出。

时间复杂度:O(n),空间复杂度 O(n)。

7. 总结

树的重心是树形结构中的一个重要概念,具有优秀的平衡性质。掌握重心的求法和性质,对于解决树相关算法问题(特别是树分治)非常有帮助。在实际编码中,只需一次 DFS 即可找到重心,代码简洁高效。

相关推荐
不会就选b1 小时前
算法日常・每日刷题--<哈希>1
算法·哈希算法
zander2581 小时前
LeetCode 207. 课程表
算法·深度优先
萌动的小火苗2 小时前
深度学习中的损失函数与优化算法基础知识
人工智能·深度学习·算法
happyprince2 小时前
02_OpenCodeReview 具体观:八种算法机制与背后的论文谱系
算法
变量未定义~2 小时前
图论+动态规划——魔法阵
算法
大爱编程♡2 小时前
C++基础-类和对象
c++·算法
ysa0510302 小时前
【板子】费用流
算法·深度优先·图论
玖玥拾2 小时前
LeetCode 80 删除有序数组中的重复项 II
算法·leetcode
青山木2 小时前
Hot 100 --- 电话号码的字母组合
java·数据结构·算法·leetcode·逻辑回归