P1395 【会议】
2019-08-19
题目描述
有一个村庄居住着n个村民,有n-1条路径使得这n个村民的家联通,每条路径的长度都为1。
现在村长希望在某个村民家中召开一场会议,村长希望所有村民到会议地点的距离之和最小,那么村长应该要把会议地点设置在哪个村民的家中,并且这个距离总和最小是多少?若有多个节点都满足条件,则选择节点编号最小的那个点。
Solve
1.每个村民的家都为一个节点,所有的边权值为1,而且这是一个树。
2.找到树的重心。
3.以树的重心为源点,求出其与各个节点的距离和(使用BFS)。
Tips
1.什么是树的重心?
链接Blog较为详细地描述了树的重心的概念。
2.为什么会议地点就是树的重心?
这是树的重心的性质运用。
Code
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std; //标准开头
const int N=50010; //节点数
int n,ans; //n——节点数,ans为树的重心
int maxn=10000000;
int u,r,sum; //u,r边的两端点,sum——距离之和
int d[N],dis[N]; //dis[i]为节点i到源点(树的重心)的距离
vector<int> G[N]; //vector建图
queue<int> q; //BFS必备队列
bool vis[N]; //BFS中已经遍历的点
void dfs(int s,int f){ //求树的重心
d[s]=1;
int res=0;
for(int i=0;i<G[s].size();i++){
if(G[s][i]==f) continue;
dfs(G[s][i],s);
d[s]+=d[G[s][i]];
res=max(res,d[G[s][i]]);
}
res=max(res,n-d[s]);
if(res<maxn||(res==maxn&&ans>s)){
maxn=res;
ans=s;
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u,&r);
G[u].push_back(r);
G[r].push_back(u);
}
dfs(1,0);
q.push(ans);
while(!q.empty()){ //标准BFS
int e=q.front();
q.pop();
vis[e]=true;
sum+=dis[e];
for(int i=0;i<G[e].size();i++){
if(!vis[G[e][i]]){
q.push(G[e][i]);
dis[G[e][i]]=dis[e]+1;
}
}
}
printf("%d %d",ans,sum); //完美输出
return 0;
}