AcWing 846. 树的重心
原题链接
简单
作者:
acm_wf
,
2021-03-20 10:53:30
,
所有人可见
,
阅读 233
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
//M很重要 边和点不可混为一谈
const int N = 1e5 + 10, M = 2 * N;
int n;
int h[N], e[M], ne[M], idx;
bool st[N];
//最终答案
int ans = N;
//存边
//u指向x
void add(int u, int x){
e[idx] = x;
ne[idx] = h[u];
h[u] = idx ++;
}
//这函数我们的需求有两个
//第一 我们需要返回以当前为根的子树的节点数目,以反向推出父结点连通集点数
//第二 我们需要知道如果当前的根去掉,子树里面连通集点数最大值
//嗯哼?第二点就可以用第一点来解决吧,叶子节点返回子树节点个数就是1
//返回子树的节点数目
int dfs(int u){
st[u] = true; //这个点已经走过了
//包括自身在内的节点个数
int sum = 1;
//去掉当前节点后,子树中连通集点数最大值
int res = 0;
for(int i = h[u]; i != -1; i = ne[i]){
if(!st[e[i]]){
//深搜搜出来就是某个分支的咯!
int s = dfs(e[i]);
//加上
sum += s;
//我们通过每一轮的回溯最后就可以判断出去掉某节点后 往叶子节点方向的联通集点数最大值
res = max(res, s);
}
}
//最后再和父结点方向比较哪个大即可
res = max(res, n - sum);
//在所有大的里面取最小的
ans = min(ans, res);
return sum;
}
int main(){
cin.tie(0);
ios::sync_with_stdio(false);
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 << endl;
return 0;
}