方法:
先找出树上最长的链,最终的两点一定是在最长的链上(这个很容易看出来),至于怎么找最长的链是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; }