重心的定义
重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。
举个例子
我们去掉1,树将分为连通块(2,5,8),(3,4,6,9),(7),此时最大连通块点数是4,去掉点2,连通块为(8),(5),(1,4,7,3,6,9),最大连通块点数是6,依次类推,我们会发现1才是树的重心。
思路
假设我们删除红色节点,那么树会划分成ABC三个部分,我们只需要算出
max(size(A),size(B),size(n-A-B))
删除点x,对于y,dfs(y) = size(B) , dfs(z) = size©, 那么size(A) = n - size(A) - size(B);
代码
# include <bits/stdc++.h>
using namespace std;
const int N = 1e5;
// 无向图n个边最多有2n个idex,每条边会出现两次
// h队列头结点,e储存元素,ne每一个结点的next指针
int n,idx;
int h[N],e[N*2],ne[N*2];
int ans = N;
bool st[N];// 状态数组
void add(int a, int b){// 头插法
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
/* 树的dfs模板
// 需要标记数组st[N], 遍历节点的每个相邻的便
void dfs(int u) {
st[u] = true; // 标记一下,记录为已经被搜索过了,下面进行搜索过程
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
dfs(j);
}
}
}
*/
int dfs(int u){
int sum = 1;// sum记录以u为根的树的节点数,包括u
st[u]= true;//标记已经使用过
int res = 0;// 记录当前节点size
for (int i = h[u]; i != -1; i = ne[i]){
int j = e[i];
if (!st[j]){
int s = dfs(j);
res = max(res, s);
sum += s;
}
}
res = max(res , n - sum);// 选择出当前节点u为重心的最大连通图节点数
ans = min(ans, res);// 选择出遍历过的最小的最大连通图节点数
return sum;
}
int main(){
cin >> n;
memset(h ,-1, sizeof(h));
for (int i = 0; i < n - 1; i ++){
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);//无向图
}
dfs(1);
cout << ans;
return 0;
}