本来呢,我是在看老师给的思考题--树的中心,然后莫名其妙就开始研究起树的重心了
不过先把思考题抬出来,下篇博客讲
思考题:求树的中心
树的中心:即求树中的点对最远距离最近。
问题:给你一棵有N个结点边权均为1的树,要求你找到树中的点,使得此点到树中的其它结点的最远距离最近。范围:N<=200000
------------------------------------------------------------------------------------------------------------------
还是讲讲树的重心吧,上题--点击打开链接
题意:给定一棵树,求树的重心的编号以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的.(其实我觉得网上给的树的重心的定义还不如poj上的英文好懂,大家自己看着办)
这显然给出来的是一个无根树,那为了方便dp我们就把其转为有根树(随便逮一个点作为根)。然后对于每一个点而言,我们可以把和它有边连接的点分为两部分,父亲那儿一堆,儿子一堆,然后只用计算儿子那里的,再用n去减,就可以得到上面父亲的了,然后再取最大值,得到当前点的balance,就over了
#include <map>
#include <cstring>
#include <iostream>
#include<vector>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 20009
using namespace std;
vector<int> q[maxn];
int t,n;
int d[maxn],f[maxn];
int minn=maxn,num=maxn;
void dfs(int u,int fa){
if(d[u]) return ;/////如果之前搜到过,就直接返回
d[u]=1;
int i,j,k,maxdown=-1,maxall;
for(i=0;i<q[u].size();++i){
int v=q[u][i];
if(v!=fa){
dfs(v,u);
d[u]+=d[v];
maxdown=max(maxdown,d[v]);//////儿子中的max
}
}
maxall=max(maxdown,n-d[u]);//////u的儿子和u的父亲的max
if(maxall<minn||maxall==minn&&num>u){//////////////////////////
minn=maxall;
num=u;
}
}
int main()
{
scanf("%d",&t);
int i,j,k,tt;
for(tt=1;tt<=t;++tt){
for(i=0;i<=maxn;++i)
q[i].clear();
scanf("%d",&n);
for(i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
q[u].push_back(v);
q[v].push_back(u);
}
memset(d,0,sizeof(d));
minn=maxn;num=maxn;/////////////一遇到多组数据的就一定要注意初始化
dfs(1,-1);
printf("%d %d\n",num,minn);
}
}