码迷,mamicode.com
首页 > 其他好文 > 详细

HDU - 4607 Park Visit (树的直径)

时间:2018-07-09 00:37:37      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:math   ret   pre   lld   scanf   main   out   就是   make   

http://acm.hdu.edu.cn/showproblem.php?pid=4607

题意

一颗n个顶点的树,现在只想访问其中k个,问最短路径长度为多少。

分析

首先,最短的路径当然是一条链。那么我们需要求树的直径。求法:先从任意一点dfs到最深处v,再以v为根深搜,得到的最长路径便是树的直径。

若k小于等于直径,那么这k个顶点肯定是处于直径路径上最优,此时答案为k-1。

若k大于直径,即需要走不在直径上的点。根据大量实践发现,每个不在直径上的点对答案的贡献都是2。因此最终答案就是k-1+(k-d)*2

#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<cstdio>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#define rep(i,e) for(int i=0;i<(e);i++)
#define rep1(i,e) for(int i=1;i<=(e);i++)
#define repx(i,x,e) for(int i=(x);i<=(e);i++)
#define X first
#define Y second
#define PB push_back
#define MP make_pair
#define mset(var,val) memset(var,val,sizeof(var))
#define scd(a) scanf("%d",&a)
#define scdd(a,b) scanf("%d%d",&a,&b)
#define scddd(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define pd(a) printf("%d\n",a)
#define scl(a) scanf("%lld",&a)
#define scll(a,b) scanf("%lld%lld",&a,&b)
#define sclll(a,b,c) scanf("%lld%lld%lld",&a,&b,&c)
#define IOS ios::sync_with_stdio(false);cin.tie(0)

using namespace std;
typedef long long ll;
template <class T>
void test(T a){cout<<a<<endl;}
template <class T,class T2>
void test(T a,T2 b){cout<<a<<" "<<b<<endl;}
template <class T,class T2,class T3>
void test(T a,T2 b,T3 c){cout<<a<<" "<<b<<" "<<c<<endl;}
const int N = 1e6+10;
//const int MAXN = 210;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const ll mod = 1000000007;
int T;
void testcase(){
    printf("Case #%d: ",++T);
}
const int MAXN = 1e5+5;
const int MAXM = 30;

struct Edge{
    int to,nxt;
}edge[MAXN<<1];

int n,m,cnt,head[MAXN];
int dis[MAXN];

void init(){
    cnt=0;
    mset(head,-1);
}
void addedge(int u,int v){
    edge[cnt].to=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}

void DFS(int u){
    for(int i=head[u];i!=-1;i=edge[i].nxt){
        int v=edge[i].to;
        if(dis[v]==-1){
            dis[v]=dis[u]+1;
            DFS(v);
        }
    }
}

int main(){
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif // LOCAL
    int t;
    scanf("%d",&t);
    while(t--){
        init();
        scdd(n,m);
        int u,v;
        for(int i=1;i<n;i++){
            scdd(u,v);
            addedge(u,v);
            addedge(v,u);
        }
        mset(dis,-1);
        dis[1]=0;
        DFS(1);
        int len=0;
        for(int i=1;i<=n;i++)
            if(dis[i]>len){
                len=dis[i];
                u=i;
            }
        mset(dis,-1);
        dis[u]=0;
        DFS(u);
        len=0;
        for(int i=1;i<=n;i++)
            if(dis[i]>len)
                len=dis[i];
        len++;
        int k;
        while(m--){
            scanf("%d",&k);
            if(len>=k)
                cout<<k-1<<endl;
            else
                cout<<(len-1)+(k-len)*2<<endl;
        }
    }
    return 0;
}

 

HDU - 4607 Park Visit (树的直径)

标签:math   ret   pre   lld   scanf   main   out   就是   make   

原文地址:https://www.cnblogs.com/fht-litost/p/9281827.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!