题意 : 给你一颗树,要你在树上的两个点建消防站 ,所有点到离他最近的消防站有一个距离w ,要求最大的距离最小; 输出距离和建设消防站的两个位置 ;
如果是只建一个消防站,显然是建在树的中心 ,也就是一颗树上最长的那条链(直径) 的中心; 就可以使得所有点到消防站的距离尽可能的小;
现在要建两个,我们就先找出树的直径 ; 然后直径分成两半, 就相当于分成了两棵树,在剩下的两棵树总 分别求出他们的直径,在直径的中心就是建消防站的地方 ;
把直径分两半,我们把中间的那条边删掉旧可以了;
如何求一颗树上的直径? 任意从一个点出发,bfs往外搜,直到搜到最后一个点u , 再从u开始bfs搜,直到搜到最后一个点v ;
u到v的这条路径就是树的直径了!
#include<cstdio> #include<cstring> #include<map> #include<vector> #include<cmath> #include<cstdlib> #include<stack> #include<queue> #include <iomanip> #include<iostream> #include<algorithm> using namespace std ; const int N=255555; const int M=N*2; const int inf=1<<30; struct node { int u,v,next; }edge[M]; int head[N],dist[N],pre[N],path[N],vist[N]; int u[M],v[M],next[M]; int top , n ,x,y,maxlen; bool vis[N],visedge[M]; void add(int u,int v) { edge[top].u=u; edge[top].v=v; edge[top].next=head[u]; head[u]=top++; edge[top].u=v; edge[top].v=u; edge[top].next=head[v]; head[v]=top++; } int bfs(int s, int w) { int now=0,to; memset(vis, 0, sizeof(vis)); vis[s] = true; dist[s] = 0; pre[s] = -1; queue<int> q; q.push(s); while(!q.empty()) { now = q.front(); q.pop(); vist[now] = w; for(int i = head[now]; i!=-1 ; i = edge[i].next) if(!visedge[i]) { to=edge[i].v; if(!vis[to]) { pre[to] = now; dist[to] = dist[now] + 1; q.push(to); vis[to] = true; } } } return now; } void solve() { int s, t, len = 0, du, dv; //找树的直径 s = bfs(1, -1); t = bfs(s, -1); for(int j = t; j!=-1; j = pre[j]) //记录直径上的点 path[len++] = j; // 删掉直径中间那条边,分成两颗树 for(int i = t, j = 0; i!=-1; i = pre[i], j++) { if((j + 1) == len / 2) { du = i; dv = pre[i]; break; } } //标记被删的那条边 for(int i = 0; i < top; i++) { int u=edge[i].u; int v=edge[i].v; if(( u == du && v == dv) || ( u == dv && v == du)) { visedge[i] = 1; } } //在剩下的两棵树中找直径 maxlen = 0 ; x = y = -1 ; for(int i = 1; i <= n; i++) if(vist[i] == -1) { s = bfs(i, 0); t = bfs(s, 0); len = 0; for(int j = t; j!=-1; j = pre[j]) path[len++] = j; //找到直径的中点,就建消防站 for(int j = t, k = 0; j!=-1; j = pre[j], k++) if((k + 1) == (len + 1) / 2) { if(x == -1) { x = j ; break; } if(y == -1) { y = j ;break; } } //距离是直径的一半 ; maxlen = max(maxlen, len / 2); } } int main() { int T,a,b; scanf("%d", &T); while(T--) { top = 0; memset(head, -1, sizeof(head)); memset(visedge, 0, sizeof(visedge)); scanf("%d", &n); for(int i = 0; i < n - 1; i++) { scanf("%d%d", &a, &b); add(a,b); } solve(); printf("%d %d %d\n",maxlen,x,y); } return 0; }