输入样例:
4
1 2
2 3
3 4
输出样例:
2 4
思路:
将题中的图看作以1为根节点的一棵树
d[i]表示所有点到i的距离之和
size[i]表示以i为根节点的子树的点的个数
假设x是y的父节点
d[y] = d[x] + (n-size[y]) + size[y]
这是一个从上到下的过程
所以我们首先可以利用宽搜求所有点到1的距离之和d[1]
然后再用一个深搜求所有点以i为根节点的子树点的个数size[i](这是一个自下而上的过程,所以要跟求d[i]的深搜分开)
再用一个深搜求所有点到点i的距离之和d[i]
结果就是最小的d[i]对应的最小的i
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N=1e5+5;
int n;
int d[N],dist[N]; //dist记录所有点到1的距离
int e[N],ne[N],h[N],idx;
int q[N],size[N];
bool st[N];
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void bfs(){
memset(dist,-1,sizeof dist);
int hh=0,tt=-1;
q[++tt]=1;
dist[1]=0;
while (hh<=tt){
int t=q[hh++];
for (int i=h[t];i!=-1;i=ne[i]){
int j=e[i];
if (dist[j]==-1){
dist[j]=dist[t]+1;
q[++tt]=j;
}
}
}
for (int i=1;i<=n;i++) d[1]+=dist[i];
}
void dfs1(int x){
st[x]=true;
size[x]=1;
for (int i=h[x];i!=-1;i=ne[i]){
int j=e[i];
if (!st[j]){
dfs1(j);
size[x]+=size[j];
}
}
}
void dfs2(int x){
st[x]=true;
for (int i=h[x];i!=-1;i=ne[i]){
int j=e[i];
if (!st[j]){
d[j]=d[x]+n-2*size[j];
dfs2(j);
}
}
}
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);
}
bfs(); //宽搜求所有点到1的距离
dfs1(1);
memset(st,false,sizeof st);
dfs2(1);
int res=1,len=d[1];
for (int i=1;i<=n;i++){
if (d[i]<len) len=d[i],res=i;
}
//for (int i=1;i<=n;i++) cout<<dist[i]<<' ';
//cout<<endl;
//for (int i=1;i<=n;i++) cout<<size[i]<<' ';
//cout<<endl;
//for (int i=1;i<=n;i++) cout<<d[i]<<' ';
//cout<<endl;
cout<<res<<' '<<len<<endl;
return 0;
}