1. 程式人生 > >[HDU4607]Park Visit(樹上最長鏈)

[HDU4607]Park Visit(樹上最長鏈)

n-1 sizeof struct decide ccf notes using feature path

先附上原題:

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(樹上最長鏈)