先求出树的直径(从一点DFS找最远点,再从最远点DFS找最远点,两个最远点的距离为直径)。然后由一条直径的两个端点分别标记距它们不超过(直径+1)/2的点,两次都被标记的就输出。 #include <iostream> #include <cstdio> #include <cstring> #define HEAD 10002 #define EDGE 20004 using namespace std; int n; int e=0,pnt[EDGE],nxt[EDGE],head[HEAD],from[EDGE],d[HEAD]; int mdeep,midx; int st,en; //最长链的两个端点 int cnt[HEAD]; void addedge(int s,int t) { pnt[e]=t; nxt[e]=head[s]; from[e]=s; head[s]=e; e++; } void Init() { e=0; memset(head,-1,sizeof(head)); memset(cnt,0,sizeof(cnt)); } void dfs(int idx,int deep) { if(deep>mdeep) { mdeep=deep; midx=idx; } d[idx]=deep; int nxt0=head[idx]; while(nxt0!=-1) { if(d[pnt[nxt0]]==-1) dfs(pnt[nxt0],deep+1); nxt0=nxt[nxt0]; } } void dfs2(int idx,int deep) { if(deep>mdeep) return; cnt[idx]++; d[idx]=deep; int nxt0=head[idx]; while(nxt0!=-1) { if(d[pnt[nxt0]]==-1) { dfs2(pnt[nxt0],deep+1); } nxt0=nxt[nxt0]; } } int main() { int fa; while(scanf("%d",&n)!=EOF) { Init(); for(int i=2;i<=n;++i) { scanf("%d",&fa); addedge(i,fa); addedge(fa,i); } mdeep=midx=-1; memset(d,-1,sizeof(d)); dfs(1,0); st=midx; mdeep=midx=-1; memset(d,-1,sizeof(d)); dfs(st,0); en=midx; mdeep=(mdeep+1)/2; memset(d,-1,sizeof(d)); dfs2(st,0); memset(d,-1,sizeof(d)); dfs2(en,0); bool fst=false; for(int i=1;i<=n;++i) { if(cnt[i]==2) { if(!fst) { printf("%d",i); fst=true; } else printf(" %d",i); } } printf("/n"); } return 0; }