多校联合 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 // n,m ; n个公圆,和m次询问, 询问访问k个公园的最小步数是多少; 3 2 1 2 4 2 2 4
 

Sample Output
  
  
1 4
题意 :
给你n公园 ,用n-1条边连接, 问访问k个公园需要的最小步数,每条边是一步. 随意访问k个公园,只要求步数最少 .
这说明,必须少走回头路, 所以,先找出这颗树的一条最长的路,公园数为L , 当 k <= L 时,说明,从最长路的头一直想着尾走,一定能访问k个公园,步数为 k-1 ; 当 k > L 时, 说明最长的路的不够k个城市, 所以,从最长路的头出发,走向尾的途中,需要访问分支的公圆,,并且访问分支的公园 后马上要返回最长路,接着继续走向尾端.所以中途访问分支的公园,访问每个公圆的步数是2 (因为要返回最长路) ,
所以得到公式, 最长路有L个公园,需要步数为 L-1 ; 还剩 k-L 公园在中途的分支上访问, 需要的步数为 2*(k-L) ;总步数为 L-1 + 2*(k-L)
现在问题就转换到,我们如何来求一颗树种,最长的路径.假设以一个树为树根, 它有 n 个字树, 如果我们知道字树中最大长度的字树, 加上1(连上树根) ;就能得出树根左端的最长路, 再把另一颗子树的值,加上1;就得到树根右边的最长路. 所以只要n个子树里求出拥有最大长度的子树和第二大的子树,再分别加1 ;就能求出最长的路径.同样,n个子树的没课子树的最大长路 又相当于把子树当场一个小树根,同上得出的 .这样,从叶子慢慢往上,最终求得最大长度. 这里用dfs搜索....
我们怎么储存给出的数据,这里用静态链表 .
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<stack> #include<map> #include<vector> #include<cmath> #include<iostream> using namespace std; const int N = (int)1e5+10; struct Edge{     int v, nxt; }edge[N<<2]; int head[N], idx; int n, m; int dp[N], cnt[N], maxlen; void AddEdge(int u,int v){ //静态链表储存 ;     edge[idx].v = v; edge[idx].nxt = head[u];     head[u] = idx++; } int dfs(int u,int pre){     int num = 0, tmp = 0;     vector<int> cnt; //用容器储存子树的最大路径,cnt[i]表示第i课子树的最大步数;     for(int i = head[u]; ~i; i = edge[i].nxt ){         int v = edge[i].v;         if( v == pre ) continue;         int x = dfs(v,u); //找到该子树的最大长度 ;返回tmp+1 ;         cnt.push_back(x); //放入容器中     }     for(int i = 0; i < (int)cnt.size(); i++)     {         maxlen = max( maxlen, tmp + cnt[i] ); //前i-1颗子树中的最大值 加上 目前搜索到的子树值 ,更新最大路径数maxlen ;         tmp = max( tmp, cnt[i] ); //tmp储存的是子树中的最大值,     }     return tmp+1; } int main(){     //freopen("1.in","r",stdin);     int _;     scanf("%d", &_);     while( _-- ){          scanf("%d%d", &n,&m);         memset( head, -1, sizeof(head));         idx = 0;         for(int i = 0; i < n-1; i++)         {             int u, v;             scanf("%d%d", &u,&v);             AddEdge( u, v ); //储存u到v这条边             AddEdge( v, u );         }         maxlen = 0; //maxlen是最大路径的边,maxlen+1就是最大路径的公园数         dfs(1, -1); //从1公园开始搜索,父结点为-1 ;        // printf("maxlen = %d\n", maxlen );         for(int i = 0; i < m; i++) //m次询问         {             int k;             scanf("%d", &k);             if( k <= maxlen+1 )  printf("%d\n", k-1 );             else{                 int x = k-maxlen-1;                 printf("%d\n", 2*x+maxlen );             }         }     }     return 0; }
求一棵树的最长路径,代码还不是很理解透.. 核心代码是 dfs() 和 静态链表储存 ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值