HDU 4607 Park Visit(树的直径)

题目链接

Claire and her little friend, ykwd, are travelling in Shevchenko's Park! The park is beautiful - but large, indeed. N feature spots in the park are connected by exactly (N-1) undirected paths, and Claire is too tired to visit all of them. After consideration, she decides to visit only K spots among them. She takes out a map of the park, and luckily, finds that there're entrances at each feature spot! Claire wants to choose an entrance, and find a way of visit to minimize the distance she has to walk. For convenience, we can assume the length of all paths are 1. 
Claire is too tired. Can you help her? 

Input

An integer T(T≤20) will exist in the first line of input, indicating the number of test cases. 
Each test case begins with two integers N and M(1≤N,M≤10 5), which respectively denotes the number of nodes and queries. 
The following (N-1) lines, each with a pair of integers (u,v), describe the tree edges. 
The following M lines, each with an integer K(1≤K≤N), describe the queries. 
The nodes are labeled from 1 to N. 

Output

For each query, output the minimum walking distance, one per line.

Sample Input

1
4 2
3 2
1 2
4 2
2
4

Sample Output

1
4

PS:题意:一个人去逛公园,想逛k个地方,但是不想走路。要求求出最少走的路的长度。

首先做这个题的时候我们要考虑树的直径,因为要是想逛的步数k小于直径上的点数这样步数是最少的,为k-1步。现在我们要考虑要走的点数大于树的直径的情况,在这种情况下,我们就要考虑走到叶子节点后要往回走。其实这个问题很容易思考到,我们还是要先走数的直径,走完了过后,再往回走,往回走一个首先要回来再走到那个节点,等于每个节点要走两段才能到达所以当k大于直径的时候最短步数len-1+(k-1)*2;len为树的直径上的节点数。

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e5+10;
const int mod=10007;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
typedef long long ll;
using namespace std;
struct node
{
    int v,next;
} rea[maxn<<1];
int head[maxn],dis[maxn],len;
void inct()
{
    me(head,-1);len=0;
}
void add(int u,int v)
{
    rea[len].v=v;
    rea[len].next=head[u];
    head[u]=len++;
}
void dfs(int u)
{
    for(int i=head[u];i!=-1;i=rea[i].next)
    {
        int v=rea[i].v;
        if(dis[v]==-1)
        {
            dis[v]=dis[u]+1;
            dfs(v);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        inct();
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1; i<n; i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y),add(y,x);
        }
        me(dis,-1);
        int u=0,t_ma=-1;
        dis[1]=0;//两次dfs求树的直径
        dfs(1);
        for(int i=1;i<=n;i++)
            if(dis[i]>t_ma)
                t_ma=dis[i],u=i;
        me(dis,-1);t_ma=0,dis[u]=0;
        dfs(u);
        for(int i=1;i<=n;i++)
            t_ma=max(t_ma,dis[i]);
        t_ma++;//因为我们算的是树的直径,直径上的节点数等于直径长度+1.
        while(q--)
        {
            int k;
            scanf("%d",&k);
            if(k<=t_ma)
                printf("%d\n",k-1);
            else
                printf("%d\n",t_ma-1+(k-t_ma)*2);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值