树形结构 —— 树与二叉树 —— 树的重心
【概述】
树的重心也叫树的质心,对于一棵具有 n 个结点的无根树,找到一个点,使得将树变为以该点为根的有根树时,最大子树的结点数最小。
简单来说,就是给定一棵 n 个点的树,当删除某点 x 后,使得最大连通块最小,此时点 x 即为树的重心。
相关性质:
- 一棵树最多有两个重心,且这两个重心相邻
- 一棵树添加或删除一个节点时,树的重心最多只移动一条边的位置
- 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上
- 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样
树的重心同样可以用 dfs 来求,设 size[i] 表示以 i 为根的子树的总大小,mson 表示以 i 为根的最大子树的大小,然后利用 dfs 维护这两个数组即可
最后只需要求所有的 max(n-size[x], mson[x]) 的最小值即为以 x 为根时最大子树的大小,其中 n-size[x] 代表删去 x 及其子树后的连通块大小
【实现】
struct Edge {
int to, val;
int next;
Edge() {}
Edge(int to, int val, int next) : to(to), val(val), next(next) {}
} edge[N];
int n;
int head[N], tot;
int size[N], mson[N];
int core, minBalance = INF;
void addEdge(int from, int to, int val) {
edge[++tot].to = to;
edge[tot].val = val;
edge[tot].next = head[from];
head[from] = tot;
}
void dfs(int x, int father) {
size[x] = 1;
mson[x] = 0;
for (int i = head[x]; i != -1; i = edge[i].next) {
int y = edge[i].to;
if (y == father)
continue;
dfs(y, x);
size[x] += size[y];
mson[x] = max(mson[x], size[y]);
}
mson[x] = max(n - size[x], mson[x]);
if (mson[x] < minBalance) {
core = x;
minBalance = mson[x];
}
}
int main() {
scanf("%d", &n);
memset(head, -1, sizeof(head));
for (int i = 1; i <= n - 1; i++) {
int x, y, val;
scanf("%d%d%d", &x, &y, &val);
addEdge(x, y, val);
addEdge(y, x, val);
}
dfs(1, 0);
printf("%d %d\n", core, minBalance);
return 0;
}