hdu4607Park Visit 树的直径

//给一棵双向树,数中边的权值为1,问对于这颗树中走k个节点的最短路径

//如果k小于这颗数的直径加1,那么走k个节点就没有重复的路,如果大于

//那么大于的节点都需要走两遍

#include<cstdio>

#include<cstring>

#include<iostream>

#include<queue>

using namespace std ;

const int maxn = 100010 ;

int head[maxn] ;

int vis[maxn] ;

struct Edge

{

int v ;

int next ;

}edge[maxn*2] ;

int nedge ;

void addedge(int u , int v)

{

edge[nedge].v = v ;

edge[nedge].next = head[u] ;

head[u] = nedge++ ;

edge[nedge].v = u ;

edge[nedge].next = head[v] ;

head[v] = nedge++ ;

}

queue<int>que ;

int ma = 0 ;

int bfs(int st)

{

while(que.size())que.pop() ;

que.push(st) ;que.push(0) ;que.push(0) ;

int pos ;

while(que.size())

{

int u = que.front() ; que.pop() ;

int step = que.front() ;que.pop() ;

int pre = que.front() ; que.pop() ;

if(step > ma)

{

ma = step ;

pos = u ;

}

for(int i = head[u] ; i !=  -1 ;i = edge[i].next)

{

int v = edge[i].v ;

if(v == pre)continue ;

que.push(v);que.push(step+1);que.push(u) ;

}

}

return pos ;

}

int main()

{

int t ;

scanf("%d" , &t) ;

while(t--)

{

int n , m ;

memset(head ,  -1 ,sizeof(head)) ;

nedge = 0 ;

scanf("%d%d" , &n , &m) ;

for(int i = 1;i < n; i++)

{

int u  ,v ;

scanf("%d%d" , &u , &v) ;

addedge(u , v) ;

}

ma = 0 ;

int pos = bfs(1) ;

bfs(pos) ;

while(m--)

{

int k ;

scanf("%d" , &k) ;

if(k <= ma+1)printf("%d\n" , k - 1) ;

else printf("%d\n" , (k - (ma+1))*2+ma) ;

}

}

return 0 ;

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-31 09:19:15

hdu4607Park Visit 树的直径的相关文章

HDU 4607 Park Visit(树的直径)

题目大意:给定一棵树,让求出依次访问k个点的最小花费,每条边的权值都为1. 思路:如果能一直往下走不回来,那么这个路径肯定是最小的,这就取决于给定的k,但是怎么确定这个能一直走的长度呢,其实这个就是树的直径,也叫作最长简单路径.找出来这个直径之后,只需和k比较一下就能确定走多少步.设直径为maxx, 如果maxx + 1== k的话,说明刚好不用回来走完最长的这个路,所以当k小于等于maxx + 1的时候就是k-1,当k大于maxx + 1的时候,除了要走完不用回来的路,肯定还要走那些用回来的,

Park Visit(树的直径)

传送门 Park Visit Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3721    Accepted Submission(s): 1667 Problem Description Claire and her little friend, ykwd, are travelling in Shevchenko's Park! T

HDU 4607 Park visit (求树的直径)

解题思路: 通过两次DFS求树的直径,第一次以任意点作为起点,找到距离该点距离最远的点,则可以证明这个点一定在树的直径上,然后以该点为起点进行DFS得到的最长路就是树的直径. 最后的询问,如果K <= D + 1则可以沿着直径走,距离为K  -  1, 如果K >= D + 1,则需要走直径旁边的分支,每访问一个点距离为2(从直径到这个点,再返回到直径上). #include <iostream> #include <cstring> #include <cstd

poj 1985 Cow Marathon 【树的直径】

题目:poj 1985 Cow Marathon 题意:给出一个树,让你求树的直径. 分析: 树的直径:树上两点之间的最大距离. 我们从任意一点出发,BFS一个最远距离,然后从这个点出发,在BFS一个最远距离,就是树的直径. AC代码: /* POJ:1985 Cow Marathon 2014/10/12/21:18 Yougth*/ #include <cstdio> #include <iostream> #include <algorithm> #include

poj1849(求树的直径)

题目链接:http://poj.org/problem?id=1849 题意:有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少? 分析:如果从某点出发遍历完一棵树再回来,那么所有边都会走两遍,而从某点有两个机器人出发去遍历,因为不用回来,所以最后那两个人距离越远越好,可以从树的直径上某个点背道而驰,那么这段距离(树的直径)只走了一遍,其他的要走两遍,所以ans=sum*2-l

SDUT OJ 3045 迷之图论 (树的直径)

题目地址:SDUT OJ 3045 这题比赛的时候想的差不多..但是总是觉得不对..写了一次就没再写,然后删了..当时没想到的是第二次求出来的就是最长链..当时想到的两次bfs找最大值(这一种方法其实结果也对..TAT..),还有找到点后在回溯减去重点等等..但总觉得好像都不太对...赛后才知道这题原来是树的直径.....牡丹江区域现场赛的时候遇到过,不过赛后也没看... 找树的直径的方法其实就是先任取一点进行bfs,找到最远的一点,这时最远的一点肯定是最长链端点之一,然后再从这一最远点开始bf

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩

ZOJ Problem Set - 3820 Building Fire Stations 【树的直径 + 操作 】

题目:problemId=5374" target="_blank">ZOJ Problem Set - 3820 Building Fire Stations 题意:给出n个点,n-1条边的一棵树.然后要在两个点上建立两个消防站.让全部点的到消防站最大距离的点的这个距离最小. 分析:首先先求这个树的直径.然后在树的直径的中点处把树分成两棵树.然后在把两棵树分别取中点的最大值就是ans值. 这个题目数据有点水了感觉... AC代码: #include <cstdi

BDFZOI 树的直径

提交次数:2 涉及知识:基础图论/BFS 描述 一棵树T的"直径"定义为结点两两间距离的最大值.给定带权树T,求T的直径长度. 输入 第一行包含2个整数N.M,表示图中共有N个结点和M条无向边.(N <= 5000,M<n)接下来M行,每行包含3个整数{u,v,w},表示有一条无向边连接结点u.v*输入保证是无环图输出一个整数,代表直径长度 样例输入 4 31 2 12 3 22 4 3 样例输出 5 代码: 1 #include<iostream> 2 #in