【图论】树的重心
树的重心的定义是,对树中的某个点,以这个点为根,然后它会拥有若干棵子树,取出最大的那棵子树的size,然后在所有点中求最小的最大的子树的size的点,这个点就是树的重心。简单来说就是找到某个点r,去掉r之后,每棵子树是长得最平均的。树的重心最多有2个(这时候重心其实是在这两点之间的边上),最少有1个。
由于所有的子树是长得最平均的,而且树的重心常规情况下都不是叶子,那么一般都会有多棵子树。其中最大的一棵子树的节点数不会超过原树规模的一半。否则,如果某个子树超过了原树规模的一半,那么除去这棵子树以外,当前节点和当前节点的其他子树加起来的数量不够原树规模的一半,那么这时候以这棵子树的树根代替当前节点会更好。(听起来有点像换根dp的思路哈哈)
只找一次重心:
copyconst int MAXN = 2e5 + 10;
int n;
vector<int> G[MAXN];
int center, center_max_siz;
int siz[MAXN];
void find_center (int u, int p) {
siz[u] = 1;
int max_siz = 0;
for (const int &v : G[u]) {
if (v == p) {
continue;
}
find_center (v, u);
siz[u] += siz[v];
cmax (max_siz, siz[v]);
}
cmax (max_siz, n - siz[u]);
if (center == 0 || max_siz < center_max_siz) {
center = u;
center_max_siz = max_siz;
}
}
void solve() {
RD (n);
for (int i = 1; i <= n; ++i) {
G[i].clear();
}
for (int i = 1; i <= n - 1; ++i) {
int u, v;
RD (u, v);
G[u].push_back (v);
G[v].push_back (u);
}
center = 0, center_max_siz = INF;
find_center (1, 0);
WT (center);
}
多次找重心,每次找到重心之后把当前点去掉,然后在子树递归找重心,复杂度nlogn(就是sum_layer)。每个点被遍历的次数正比于其layer。
copyconst int MAXN = 2e5 + 10;
int n;
vector<int> G[MAXN];
int center, center_max_siz;
int siz[MAXN];
int layer[MAXN];
void find_center (int u, int p, int cur_n) {
siz[u] = 1;
int max_siz = 0;
for (const int &v : G[u]) {
if (v == p || layer[v] != 0) {
continue;
}
find_center (v, u, cur_n);
siz[u] += siz[v];
cmax (max_siz, siz[v]);
}
cmax (max_siz, cur_n - siz[u]);
if (center == 0 || max_siz < center_max_siz) {
center = u;
center_max_siz = max_siz;
}
}
void find_all_centers (int root, int cur_n, int l) {
if (layer[root] != 0) {
return;
}
center = 0, center_max_siz = INF;
find_center (root, 0, cur_n);
layer[center] = l;
find_center (center, 0, cur_n); // 重新计算正确的siz[v]
for (const int &v : G[center]) {
find_all_centers (v, siz[v], l + 1);
}
}
void solve() {
RD (n);
for (int i = 1; i <= n; ++i) {
G[i].clear();
layer[i] = 0;
}
for (int i = 1; i <= n - 1; ++i) {
int u, v;
RD (u, v);
G[u].push_back (v);
G[v].push_back (u);
}
find_all_centers (1, n, 1);
ll sum_layer = 0;
for (int i = 1; i <= n; ++i) {
sum_layer += layer[i];
}
WT (sum_layer);
WTN (layer, n);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
2021-04-10 【算法 - 数据结构】主席树