嘛是树的重心?
树的重心也叫树的质心。找到一个点,其所有的子树中最大的子树节点数最少,
那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡。
所有的子树中最大的子树节点数最少,这句话需要细细的品味。
所有的子树中最大的子树节点数最少 是嘛意思?
在求树的重心的时候,我们需要删除一个点,至于为什么要这样做,我的拙见
是现在会求就行了,大佬们研究出来的算法就是让我们用的(不喜勿喷)。
那么我们究竟应该删除哪个节点以满足我们的要求呢?
我们可以按照树形 DP 的思想由下到上进行尝试,找到符合
所有的子树中最大的子树节点数最少 这个条件的。
我们删除一个节点后会出现很多的分支,我们要使得这些分支中最大的最小。
用图来解释一下:
当我们删除 1 号节点时,各分支的大小为 3(3、6、7) 3(2、5、4) 最大为 3
当我们删除 2 号节点时,各分支的大小为 1(5) 1(4) 4(1、3、6、7) 最大为 4
我们要从 最大的里面找一个最小的,即删除一号节点的 3,所以这棵树的重心是 3.
树的重心有嘛性质?
树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样。
把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上。
一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置。
一棵树最多有两个重心,且相邻。
Code:
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int head[maxn],Next[maxn],edge[maxn],ver[maxn];
int Size[maxn],vis[maxn];
int tot = 0,u,v;
int n,min_port = INF,center;
void add(int u,int v) {
ver[++ tot] = v,Next[tot] = head[u];
head[u] = tot;
return ;
}
void DFS(int u) {
// 标记,初始化每个节点的大小为 1
vis[u] = 1,Size[u] = 1;
// 存储要删除的节点的所有的子树中最大的一颗子树的大小
int max_port = 0;
for(int i = head[u]; i; i = Next[i]) {
int y = ver[i];
if(vis[y]) continue;
DFS(y);
// 向上走
Size[u] += Size[y];
// 比较得到最大的
max_port = max(max_port,Size[y]);
}
// 得到删除当前节点后,节点数量最多的连通块
max_port = max(max_port,n - Size[u]);
// 找到最大中的最小的
if(max_port < min_port) {
min_port = max_port;
center = u;
}
return ;
}
int main(void) {
scanf("%d",&n);
for(int i = 1; i < n; i ++) {
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
// 将无根树转化成有根树
DFS(1);
printf("min_port = %d
center = %d
",min_port,center);
return 0;
}
测试:
9
1 2
1 7
1 4
2 8
2 5
4 3
4 6
3 9
Answer: