题目描述
有一个村庄居住着n个村民,有n-1条路径使得这n个村民的家联通,每条路径的长度都为1。现在村长希望在某个村民家中召开一场会议,村长希望所有村民到会议地点的距离之和最小,那么村长应该要把会议地点设置在哪个村民的家中,并且这个距离总和最小是多少?若有多个节点都满足条件,则选择节点编号最小的那个点。
输入
第一行。一个数n,表示有n个村民。
接下来n-1行,每行两个数字a和b,表示村民a的家和村民b的家之间存在一条路径。
输出
一行输出两个数字x和y
x表示村长将会在哪个村民家中举办会议
y表示距离之和的最小值
样例输入 Copy
4
1 2
2 3
3 4
样例输出 Copy
2 4
提示
70%数据n<=1000
100%数据n<=50000
解析:
突破口:找到一点,使得其他点到他的距离之和最小
套路题,树的重心
所以我们dp求解树的重心。
然后dfs求其他点到重心的距离。或者bfs求都可以
下面写了bfs求距离的,注释掉的是dfs求距离。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10;
vector<int> G[N];
int a,b;
int f[N];
int dep[N];
int vis[N];
int maxpos=0;
int maxsum=0x3f3f3f3f;
int n;
int res=0;
void dfs(int u,int fa)
{
f[u]=1;int maxn=0;
for(int i=0;i<G[u].size();i++)
{
int j=G[u][i];
if(j==fa) continue;
dfs(j,u);
f[u]+=f[j];
maxn=max(maxn,f[j]);
}
maxn=max(maxn,n-f[u]);
if(maxn<maxsum||(maxn==maxsum&&(maxpos>u)))
{
maxsum=maxn;
maxpos=u;
}
}
void dfs2(int u,int fa,int cnt)
{
dep[u]=cnt;
for(int i=0;i<G[u].size();i++)
{
int j=G[u][i];
if(j==fa) continue;
dfs2(j,u,cnt+1);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++)
{
cin>>a>>b;
G[a].push_back(b);
G[b].push_back(a);
}
dfs(1,-1);
queue<int> q;
q.push(maxpos);
dep[maxpos]=0;
vis[maxpos]=1;
while(q.size())
{
int t=q.front();
q.pop();
res=res+dep[t];
for(int i=0;i<G[t].size();i++)
{
int j=G[t][i];
if(j==t) continue;
if(vis[j]==1) continue;
dep[j]=dep[t]+1;
vis[j]=1;
q.push(j);
}
}
/* dfs2(maxpos,maxpos,0);
for(int i=1;i<=n;i++)
{
// cout<<dep[i]<<endl;
res=res+(dep[i]-dep[maxpos]);
}*/
cout<<maxpos<<" "<<res<<endl;
}