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

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

相关推荐
致Great6 小时前
Pi 的上下文压缩,到底是怎么工作的?
算法
watersink7 小时前
机器学习聚类算法
算法·机器学习·聚类
luj_17688 小时前
桥牌思维启示:系统设计的模块化架构
c语言·开发语言·c++·经验分享·算法
饼饼学习空间智能10 小时前
家庭服务机器人训练数据怎么积累?仿真、真实采集与持续学习的技术路线分析
人工智能·算法·机器学习
蛋先生DX11 小时前
你瘦不下来但大模型可以:量化原理了解一下
深度学习·算法·llm
牛阿大12 小时前
LQR算法
算法
(╹◡╹)13 小时前
18.剪枝
算法·机器学习·剪枝
Fa_Mian_Tuan14 小时前
图论基础|邻接矩阵超详细讲解(含无向/有向/带权图+完整可运行C语言代码)
c语言·数据结构·笔记·算法·图论
hanhahai14 小时前
指针与函数(函数指针与指针函数)
算法