求树的重心
作者:
bearono
,
2024-05-21 20:27:38
,
所有人可见
,
阅读 18
定义:树中所有的子树中最大的子树的节点数最少的节点叫做树的重心。
如何求?
1.设1为根节点,开始dfs,期间需要标记数组(看是否走过),树的数组(存以每个节点作为根节点的子树大小,节点个数),最大子树和最大子树最少节点变量
2.先去遍历根节点的出点,对于没走过的,s存调出这个子树的节点个数,ans去累加每个子树,max求哪个子树更大
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct no
{
int x,s;//重心和节点
}p;
vector<int>g[N];//存图
int n,x,y;
bool st[N];
int t[N],mins=1e9,ans1,ans2;//b记录走没走过
void bfs(int x)
{
queue<no>q;
q.push({x,0});
while(q.size())
{
auto t=q.front();
q.pop();
if(st[t.x])continue;
st[t.x]=true;
//入队,贡献是其节点个数
ans2+=t.s;
for(auto &w:g[t.x])
{
q.push({w,t.s+1});//节点个数+1
}
}
}
int dfs(int u)
{
int ans=0,maxs=0;
for(auto &w:g[u])
{
if(st[w])continue;
st[w]=true;
int s=dfs(w);
maxs=max(maxs,s);//求最大子树
ans+=s;
st[w]=false;
}
//求最大子树
maxs=max(maxs,n-ans-1);
//最大子树求最小节点
if(maxs<mins)mins=maxs,ans1=u;//ans1记录是哪个节点
else if(maxs==mins)ans1=min(ans1,u);//求最小节点,取更小的
return t[u]=ans+1;//每个子树的节点个数
}
int main()
{
scanf("%d",&n);
int m=n-1;
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
//每个节点作为根节点的子树中的节点个数
st[1]=true;//标记
dfs(1);
//cout<<ans1;
memset(st,false,sizeof st);
//从重心开始bfs
bfs(ans1);
printf("%d %d",ans1,ans2);
return 0;
}