题意:给定一棵树,从树中的任意选一个顶点出发,遍历K个点的最短距离是多少?(每条边的长度为1)
解析:就是求树的最长链,假设求出的树的最长链所包含的点数为m,那么如果K<=m,那么答案就是K-1,否则就是(K-m)*2+m-1
找树中最长链方法是:
可以通过经典的O(n)的算法求出树的直径。做法是从任意一点开始DFS或者BFS一次求出一个最远的点,这是直径的一个端点;
再从这个最远点开始再次DFS或者BFS,再找到的最远点就是直径的另外一个端点。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N=200010;
int head[N],to[N],next[N],w[N];
int dis[N],que[N];
bool vis[N];
int edge,m,n;
void init()
{
memset(head,-1,sizeof(head));
edge=0;
}
void add(int u,int v,int c)
{
to[edge]=v,w[edge]=c,next[edge]=head[u],head[u]=edge++;
to[edge]=u,w[edge]=c,next[edge]=head[v],head[v]=edge++;
}
void bfs(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
int l,r,v,u;
l=r=0;
vis[s]=1;
dis[s]=0;
que[r++]=s;
while(r>l)
{
u=que[l++];
for(int i=head[u]; ~i; i=next[i])
{
if(!vis[v=to[i]])
{
vis[v]=1;
dis[v]=dis[u]+w[i];
que[r++]=v;
}
}
}
}
int treediameter(int s)
{
int u,maxl;
bfs(s);
maxl=0,u=s;
for(int i=1; i<=n; i++)
if(dis[i]>maxl)
u=i,maxl=dis[i];
bfs(u);
maxl=0;
for(int i=1; i<=n; i++)
if(dis[i]>maxl)
maxl=dis[i];
return maxl;
}
int main()
{
int u,v,d=1,t,i,j,x;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add(u,v,1);
}
int ans=treediameter(1);
ans++;
while(m--)
{
scanf("%d",&x);
if(x<=ans) printf("%d\n",x-1);
else printf("%d\n",(x-ans)*2+ans-1);
}
}
return 0;
}