HDU4607 Park Visit

问题链接HDU4607 Park Visit

题意简述莱克尔和她的朋友到公园玩,公园很大也很漂亮。公园包含n个景点通过n-1条边相连。克莱尔太累了,所以不能去参观所有点景点。经过深思熟虑,她决定只访问其中的k个景点。她拿出地图发现所有景点的入口都很特殊。所以她想选择一个入口,并找到一条最短的路来参观k个景点。假设景点之间的距离为1。

输入数据:先输入测试用例数t,每个测试用例数据包括N和M,N为节点数,M为需要查询的上述的k(参观M个景点)

输出数据:对于各个M,输出需要走的距离。

问题分析:n个节点n-1条边构成无向无环树。该问题就是求树直径,树直径即树上最长路径。假设树直径包含m个节点(直径为m-1),若k<=m,则答案为k-1,否则答案为m + (k-m-1)*2。

程序说明:函数dfs()用于计算树直径经过的节点数。其他都是套路。

这个程序在穷尽搜索的基础上做了一些剪枝。相比较而言,这个程序速度上会稍微慢一些。另外一种解法参见:HDU4607 Park Visit(解法二)

AC的C++语言程序如下:

/* HDU4607 Park Visit */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;

const int MAXN = 100000;
vector<int>tree[MAXN+1];
bool visit[MAXN];

int maxlen;         // 树的最大直径
// DFS求最大树的直径
int dfs(int u)
{
   visit[u] = true;
   int max=0, lastmax=0, size;

   size = tree[u].size();
   for(int i=0; i<size; i++){
        if(visit[tree[u][i]])
            continue;
        int temp = dfs(tree[u][i]);
        if( temp + 1  > max){
            lastmax = max ;
            max = temp + 1;
        }else if( temp + 1 > lastmax)
            lastmax = temp + 1;
        if( maxlen < max + lastmax)
            maxlen = max + lastmax;
   }

   return max;
}

int main(void)
{
    int t, n, m, u, v, k;

    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);

        for(int i=1; i<=n; i++)
            tree[i].clear();

        for(int i=1; i<n; i++) {
            scanf("%d%d", &u, &v);
            tree[u].push_back(v);
            tree[v].push_back(u);
        }

        memset(visit, false, sizeof(visit));
        maxlen = 0;
        dfs(1);

        while(m--) {
            scanf("%d", &k);
            if(k <= maxlen)
                printf("%d\n", k-1);
            else
                printf("%d\n", maxlen + (k-maxlen-1)*2);
        }
    }

    return 0;
}


转载于:https://www.cnblogs.com/tigerisland/p/7564347.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值