树的重心
一、定义
树的某个节点,当去掉该节点后,树的各个连通分量中,节点数最多的连通分量其节点数达到最小值;
二、性质
- 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。
- 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。
- 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。
- 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。
三、求法
用搜索,搜索出以每个结点为根节点的子树上的节点个数,为子联通分量,则其的父连通分量为总个数减去子联通分量,再找到最小值即可;
四、代码
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAXN 105
using namespace std;
int n, dp[MAXN], dp1[MAXN], ans = 2147483647, ans1[MAXN], len, sum;
bool flag[MAXN];
vector < int > g[MAXN];
void dfs(int i) {
dp[i] = 1;
flag[i] = true;
for (int t = 0; t < g[i].size(); t++) {
int v = g[i][t];
if (!flag[v]) {
dfs(v);
dp1[i] = max(dp1[i], dp[v]);
dp[i] += dp[v];
}
}
dp1[i] = max(dp1[i], n - dp[i]);
return;
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int x, y;
scanf("%d %d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1);
for (int i = 1; i <= n; i++) {
if (dp1[i] < ans) {
ans = dp1[i];
len = 1;
ans1[len] = i;
} else if (dp1[i] == ans) {
ans1[++len] = i;
}
}
printf("%d\n", len);
for (int i = 1; i <= len; i++) {
printf("%d\n", ans1[i]);
}
return 0;
}