[HDU4607]Park Visit(树上最长链)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HDU4607]Park Visit(树上最长链)相关的知识,希望对你有一定的参考价值。
先附上原题:
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?
输入格式
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≤105), 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.
输出格式
For each query, output the minimum walking distance, one per line.
样例输入输出
输入
1 4 2 3 2 1 2 4 2 2 4
输出
1 4
题意:
给定一棵树,从树中的任意选一个顶点出发,遍历K个点的最短距离是多少?(每条边的长度为1)
分析:
很自然的联想到求一遍最长链。设最长链长度为len
如果K < len + 1,那么答案就为K - 1,因为只需在最长链上走就行了。
如果K > len + 1;那么肯定不能不重复的遍历完K个点,一定有些点会重复遍历。这样就有些点的子树需要重复遍历,我们肯定不会去选取最长链重复遍历。
就是最长链上的点为根,不包含最长链的子树重复遍历。那么答案就变成了 len + (K - len - 1) * 2
树上最长链:
求树上最长链的方法是用dp来求的。
f1表示从一个点子树里的最长链,f2表示一个点子树里的次长链。维护一下,然后答案为每个点f1 + f2的之中的最大值
int dfs(int u,int pre){ for(int i = head[u];i;i = edge[i].next){ int v = edge[i].to; if(v == pre)continue; dfs(v,u); if(f1[u] < f1[v] + edge[i].dis) { f2[u] = f1[u]; f1[u] = f1[v] + edge[i].dis; } else f2[u] = max(f2[u],f1[v] + edge[i].dis); } ans = max(ans,f1[u] + f2[u]); return ans; }
贴上AC代码:
# include <iostream> # include <cstdio> # include <cstring> # include <algorithm> using namespace std; const int N = 1e5 + 10002; const int M = 2e5 + 10002; const int INF = 0x3f3f3f3f; int n,m,cnt,head[N]; int read() { int ans=0,f=1; char i=getchar(); while(i<‘0‘||i>‘9‘){if(i==‘-‘)f=-1;i=getchar();} while(i>=‘0‘&&i<=‘9‘){ans=ans*10+i-‘0‘;i=getchar();} return ans*f; } struct Edge{ int to,next; int dis; }edge[M]; void AddEdge(int u,int v,int res){ Edge E1 = {v,head[u],res}; edge[++cnt] = E1;head[u] = cnt; Edge E2 = {u,head[v],res}; edge[++cnt] = E2;head[v] = cnt; } long long f1[N],f2[N],ans; int dfs(int u,int pre){ for(int i = head[u];i;i = edge[i].next){ int v = edge[i].to; if(v == pre)continue; dfs(v,u); if(f1[u] < f1[v] + edge[i].dis) { f2[u] = f1[u]; f1[u] = f1[v] + edge[i].dis; } else f2[u] = max(f2[u],f1[v] + edge[i].dis); } ans = max(ans,f1[u] + f2[u]); return ans; } void Init(){ memset(head,0,sizeof head); memset(f1,0,sizeof f1); memset(f2,0,sizeof f2); cnt = ans = 0; } void Getmap(){ Init(); n = read(), m = read(); int x,y,z; for(int i = 1;i < n;i++){ x = read();y = read(); AddEdge(x,y,1); } dfs(1,-1); ans += 1; for(int i = 1;i <= m;i++){ x = read(); if(x <= ans)printf("%d\n",x - 1); else printf("%d\n",ans - 1 + (x - ans) * 2); } } int main(){ int T; T = read(); while(T--) Getmap(); return 0; }
以上是关于[HDU4607]Park Visit(树上最长链)的主要内容,如果未能解决你的问题,请参考以下文章