题意:给一棵树,要求找出两个点,使得所有点到这两个点中距离与自己较近的一个点的距离的最大值(所有点的结果取最大的值,即最远距离)最小。 意思应该都能明白。
解法:考虑将这棵树摆直如下:
那么我们可以把最中间的那条直径边删掉,然后在分成的两颗子树内求一个直径中心点,那么这两个点就可以作为答案。 反正当时就觉得这样是正确的, 但是不能证明。
于是,几个bfs就可以搞定了。
当时写TLE了,原因是存要删的边我用了map<pair<int,int>,int>, 后来改掉就不T了,map这种东西还是尽量少用。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <string> #include <vector> #include <queue> using namespace std; #define N 200007 int vis[N],fa[N]; int maxi,maxtag; struct node { int dis,u; }; vector<int> G[N]; int U,V; void bfs(int S) { node now; now.u = S; now.dis = 0; maxi = 0, maxtag = S; queue<node> que; fa[S] = -1; memset(vis,0,sizeof(vis)); que.push(now); vis[S] = 1; while(!que.empty()) { node tmp = que.front(); que.pop(); int dis = tmp.dis; int u = tmp.u; if(dis > maxi) //最远的点 maxi = dis, maxtag = u; for(int i=0;i<G[u].size();i++) { int v = G[u][i]; if(vis[v]) continue; if((u == U && v == V)||(u == V && v == U)) continue; now.dis = dis+1; now.u = v; fa[v] = u; vis[v] = 1; que.push(now); } } } int Smaxi,Smaxtag; int Emaxi,Emaxtag; void findcenter(int S,int& ma,int& tag) { ma = 0, tag = S; bfs(S); int NS = maxtag; bfs(NS); int NE = maxtag; int cnt = (maxi+1)/2; int nc = 0; int i = NE; while(1) { nc++; if(nc > cnt) { tag = i; break; } i = fa[i]; } bfs(tag); ma = maxi; } int main() { int t,n,i,u,v; scanf("%d",&t); while(t--) { U = V = -1; scanf("%d",&n); for(i=0;i<=n;i++) G[i].clear(); for(i=1;i<n;i++) { scanf("%d%d",&u,&v); G[u].push_back(v); G[v].push_back(u); } bfs(1); int S = maxtag; bfs(S); int E = maxtag; int cnt = (maxi+1)/2; int nc = 0; i = E; while(1) { nc++; if(nc >= cnt) { U = i, V = fa[i]; break; } i = fa[i]; } findcenter(S,Smaxi,Smaxtag); findcenter(E,Emaxi,Emaxtag); printf("%d %d %d ",max(Smaxi,Emaxi),Smaxtag,Emaxtag); } return 0; }