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

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 即可找到重心,代码简洁高效。

相关推荐
阳明山水7 分钟前
CEDAR双重解耦实现决策与干预分离
人工智能·深度学习·算法·机器学习·架构
Zootopia62633 分钟前
美国载人飞船Crew-13明晚发射!
人工智能·算法·机器学习·数学建模·无人机·创业创新·信息与通信
zhangfeng11331 小时前
qjlDim 含义 TurboQuant QJL Quantized Johnson-Lindenstrauss,量化JL随机投影
人工智能·算法·ai编程·npu
HwJack201 小时前
【HarmonyOS开发小实践】HarmonyOS GC 引用计数 vs 对象追踪,三种回收算法
jvm·算法·harmonyos
blxr_1 小时前
力扣hot100前k个高频元素https://leetcode.cn/problems/top-k-frequent-elements/
算法·leetcode·职场和发展
longlongzihan10 小时前
LeetCode 17电话号码的字母组合:回溯算法(DFS)详解
c++·算法·leetcode·深度优先
封印师请假去地球钓鱼11 小时前
边解边变的问题:从“决策依赖“一词出发
人工智能·算法
今晚打老虎11 小时前
c++之提高A(前缀和)(第三课)
数据结构·c++·算法
不会就选b12 小时前
算法日常・每日刷题--<贪心>26
数据结构·算法
hetao173383714 小时前
2026-09-29 hetao1733837 的刷题记录
c++·算法