很裸的求树的重心。
题意是给出一棵树,然后求树中一个点,使得他到树上最远点的距离最小。
首先树的直径比较好求,就是先固定一个点,然后求这个点在树上的最远点,然后再从这个最远点再求一次最远点,两次得到的最远点就是树的直径的两个端点。然后发现求树的重心,就是求最远点,很明显树上所有点的最远点都在直径的两个端点上,那么重心就一定在直径上了。这样就简单了,找直径的中位点就是重心了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <queue>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,102400000")
#define N 10005
#define M 20005
#define INF 1000000007
#define LINF 1000000000000001LL
#define LL long long
#define ULL unsigned long long
#define UINT unsigned int
#define clr(x,v); memset(x,v,sizeof(x));
struct node
{
int to,next;
} edge[M];
int head[N],esum;
int n;
vector<int>inDia;
vector<int>::iterator it;
bool vis[N];
int dis[N];
inline void init()
{
memset(head,-1,sizeof(head));
esum=0;
}
inline void add(int u,int v)
{
//cout<<u<<"->"<<v<<endl;
edge[esum].to=v,edge[esum].next=head[u],head[u]=esum++;
}
int s,t;
void Debug()
{
cout<<"----debug----"<<endl;
for(it=inDia.begin(); it!=inDia.end(); it++)
cout<<*it<<" ";
cout<<endl;
}
bool findPath(int now,int pre)
{
vis[now]=1;
if(now==t) return 1;
for(int i=head[now],v; ~i; i=edge[i].next)
{
v=edge[i].to;
if(!vis[v])
if(findPath(v,now))
{
inDia.push_back(v);
return 1;
}
}
return 0;
}
void findDia()
{
queue<int>q;
for(int i=1; i<=n; i++) dis[i]=INF;
dis[1]=0;
q.push(1);
s=1;
clr(vis,0);
vis[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u],v; ~i; i=edge[i].next)
{
v=edge[i].to;
if(!vis[v])
{
vis[v]=1;
q.push(v);
dis[v]=dis[u]+1;
if(dis[v]>dis[s]) s=v;
}
}
}
//cout<<s<<endl;
for(int i=1; i<=n; i++) dis[i]=INF;
q.push(s);
t=s;
clr(vis,0);
vis[t]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u],v; ~i; i=edge[i].next)
{
v=edge[i].to;
if(!vis[v])
{
vis[v]=1;
q.push(v);
dis[v]=dis[u]+1;
if(dis[v]>dis[t]) t=v;
}
}
}
//cout<<t<<endl;
clr(vis,0);
findPath(s,-1);
inDia.push_back(s);
//Debug();
}
int main()
{
int u;
while(~scanf("%d",&n))
{
init();
for(int i=2; i<=n; i++)
{
scanf("%d",&u);
add(u,i);
add(i,u);
}
inDia.clear();
findDia();
int ans;
if(inDia.size()%2)
{
ans=inDia.size()/2;
printf("%d\n",inDia[ans]);
}
else
{
int a=inDia.size()/2;
int b=a-1;
if(inDia[a]>inDia[b]) swap(a,b);
printf("%d %d\n",inDia[a],inDia[b]);
}
}
return 0;
}