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

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

相关推荐
企业数字化笔记15 小时前
视频人体姿态怎么做三维可视化?2D关键点、深度局限与技术选型
人工智能·算法·音视频
?abc!16 小时前
(数组)581. 最短无序连续子数组
数据结构·算法·leetcode
小郎君65819 小时前
MPTT树复选框的半选状态:一棵百万节点树从递归到计数器,再到区间覆盖
算法
酌沧19 小时前
MemT让记忆成为模型内生能力
jvm·人工智能·算法
Shimeri19 小时前
越卷越像:我用遗传算法做了个"内卷"实验
算法·three.js·数据可视化·遗传算法·进化算法
Evand J20 小时前
【PMSM例程1】永磁同步电机(PMSM)转速与转子电角度观测算法|基于扩展卡尔曼滤波(EKF)的传感器状态估计与误差。附下载链接
算法·电机·1024程序员节·卡尔曼滤波
guo_wen_qiang20 小时前
二叉树的层序遍历-使用双端队列Deque
算法·leetcode·1024程序员节
爱读书的小胖20 小时前
LeetCode 55 跳跃游戏 C 语言解题分析
c语言·数据结构·算法·leetcode·1024程序员节
CCblandy20 小时前
前缀缓存命中率不靠引擎靠排列:本机仿真 3 轮,易变字段放开头 98.0%→0.0%
人工智能·python·算法·自然语言处理·性能优化
上班摸鱼下班游戏20 小时前
Unity 仿生智能算法 从蚁群算法 开始
算法·unity·游戏引擎