树的重心
求重心的本质,其实就是枚举每一个节点的所有子树,使得该节点中的最大子树最小化。
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 10;
int e[N],h[N],ne[N],mds[N],ds[N],rt,idx,n;
// mds代表所有子树中最大的子树,ds代表所有子树的总和,rt代表重心
void add(int a,int b) {
e[idx] = b;
ne[idx] = h[a];
h[a] = idx ++;
}
void dfs(int u,int fa) {
mds[u] = 0;
ds[u] = 1;
for(int i = h[u]; ~i;i = ne[i]) {
int j = e[i];
if(j == fa) continue;
dfs(j,u);
ds[u] += ds[j];// 算出所有子树的总和
mds[u] = max(mds[u],ds[j]);// 求出所有子树中最大的子树
}
mds[u] = max(mds[u], n - ds[u]);// 把父节点也看作一颗子树
if(rt == 0 || mds[u] < mds[rt]) rt = u;
if(mds[u] == mds[rt] && u < rt) rt = u;// 取编号较小的一个点
}
int main() {
int t;
cin >> t;
while(t --) {
memset(mds,0,sizeof mds);
memset(ds,0,sizeof ds);
memset(h,-1,sizeof h);
rt = idx = 0;
cin >> n;
for(int i = 0;i < n - 1; ++i) {
int a,b;
cin >> a >> b;
add(a,b);
add(b,a);
}
dfs(1,0);
cout << rt <<' ' << mds[rt] << endl;
}
return 0;
}
模板题