方法:
先找出树上最长的链,最终的两点一定是在最长的链上(这个很容易看出来),至于怎么找最长的链是modiz教我的。。。。。
先以树上任意一点为根节点找出最深的点pre,再以pre为根节点找出最深的点v,那么最长的链就是pre-v这条链(感觉有点吊,完全想不到啊)
找出最长的链后,找出树的中点,然后从树的中间切开变成两个子树,求这两个子树的中点即可((⊙_⊙)?这样为什么会对。。。)
遍历树的时候,首先用的dfs,发现溢出了,必须要用bfs遍历
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 200010
struct node
{
int p;
int depth;
node(int x, int y):
p(x),depth(y){}
node(){}
};
int F[maxn], h[maxn];
int maxd;
vector<int>aa[maxn];
queue<node> q;
void bfs(int &x)
{
while(!q.empty())
{
node N= q.front();
q.pop();
//printf("%d\n",N.p);
if(N.depth> maxd)
{
x= N.p;
maxd= N.depth;
}
for(int i= 0; i< aa[N.p].size(); i++)
if(!h[aa[N.p][i]])
{
h[aa[N.p][i]]= 1;
node M;
M.p= aa[N.p][i];
M.depth= N.depth + 1;
F[M.p]= N.p;
q.push(M);
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
int n, a, b;
scanf("%d",&n);
for(int i= 1; i<= 200000; i++)
aa[i].clear();
for(int i= 1; i<= n-1; i++)
{
scanf("%d %d",&a, &b);
aa[a].push_back(b);
aa[b].push_back(a);
}
if(n== 2)
{
printf("0 1 2\n");
continue;
}
int pre, v;
memset(h, 0, sizeof h);
h[1]= 1, maxd= 1, pre= 1; //以点1为根节点建树
q.push(node(1,1));
bfs(pre);
// printf("pre=%d\n",pre);
memset(h, 0, sizeof h);
memset(F, -1, sizeof F);
h[pre]= 1, maxd= 1, v= pre; //以pre点为根节点建树
q.push(node(pre, 1));
bfs(v);
// printf("v= %d\n",v);
// printf("maxd=%d\n",maxd);
/*ans= (maxd-2)/4;
if((maxd-2)%4)
ans++;*/
int xx; //整棵树的中点
for(int i= v, j= 1; i!= -1; i= F[i], j++)
//这个链是从pre起,v结束所以一定要这样找中点,
//因为我待会删除的边是xx与F[xx]之间的边,
//所以不这样遍历会错,下面那种for(int i= ppre, j= maxd/2; i!= -1; i= F[i], j--)是因为子树最长的链的两个中点任取一个都行(假如有两个中点)
{
// printf("%d %d\n",i,j);
if(2*j>= maxd)
{
xx= i;
break;
}
}
// printf("xx=%d F[xx]=%d\n",xx,F[xx]);
for(int i= 0; i< aa[xx].size(); i++)
if(aa[xx][i]== F[xx])
{
aa[xx].erase(aa[xx].begin()+i, aa[xx].begin()+i+1);
break;
}
for(int i= 0; i< aa[F[xx]].size(); i++)
if(aa[F[xx]][i]== xx)
{
aa[F[xx]].erase(aa[F[xx]].begin()+i, aa[F[xx]].begin()+i+1);
break;
}
//把这棵树分成两棵树求中点
int ppre= pre;
memset(h, 0, sizeof h);
memset(F, -1, sizeof F);
h[pre]= 1, maxd= 1;
q.push(node(pre, 1));
bfs(ppre); //包含pre点的子树
// printf("ppre=%d\n",ppre);
int ans= 0, p1= -1, p2= -1;
for(int i= ppre, j= maxd/2; i!= -1; i= F[i], j--)
if(j== 0)
{
p1= i;
break;
}
ans= max(ans, maxd/2); //p1为第一颗子树的中点
int vv= v;
memset(h, 0, sizeof h);
memset(F, -1, sizeof F);
h[v]= 1, maxd= 1;
q.push(node(v, 1));
bfs(vv); //包含v点的子树
// printf("vv=%d\n",vv);
for(int i= vv, j= maxd/2; i!= -1; i= F[i], j--)
if(j== 0)
{
p2= i;
break;
}
ans= max(ans, maxd/2);
printf("%d %d %d\n",ans, p1, p2);
}
return 0;
}