HDU4607 Park Visit

肯定会想到树的直径

如果直径够长,就在直径(1+8)上面找路径,ans=k

如果不够长,肯定会在有点分叉点(如3,4,5)回溯,然后我们把路径拉直,把其中一条的作为主线(有机化学,ORZ),主线是线走一遍,而分支走两遍,所以要想答案越小,主线就要求越长,也就是树的直径d,ans=d+(k-d)*2

如果不好想,可以模拟一下,1--2--3--上--下--4--下--下--上--上--5--上--下--下--上-- 6--7--8....

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;
int dis[100010],ans[100010],Max;
int n,s,t;
vector<int>G[100010];
void _dfs(int v)
{
    for(int i=0;i<G[v].size();i++){
        if(!dis[G[v][i]]) {
            dis[G[v][i]]=dis[v]+1;
            _dfs(G[v][i]);
        }//任意两个点只有一条路,所以dfs和bfs效果一样 
    }
}
void _finds()
{
      memset(dis,0,sizeof(dis));
      dis[1]=1;_dfs(1);s=1;
      for(int i=2;i<=n;i++)
         if(dis[i]>dis[s]) s=i;
}
void _findt()
{
      memset(dis,0,sizeof(dis));
      dis[s]=1;_dfs(s);t=1;
      for(int i=2;i<=n;i++)
       if(dis[i]>dis[t]) t=i; 
      Max=dis[t];
}
int main()
{ 
     int i,j,k,u,v,T,d,m;
     scanf("%d",&T);
     while(T--){
            scanf("%d%d",&n,&m);
            Max=0;
            for(i=1;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);
            }
            _finds();
            _findt();
            for(i=1;i<=m;i++){
                scanf("%d",&d);
                if(d<=Max) printf("%d
",d-1);
                else printf("%d
",Max-1+(d-Max)*2);
            }
     }
     return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/7681305.html