您的位置:首页 > 其它

HDU 4607 Park Visit (DP最长链)

2013-07-28 12:20 387 查看
【题目】题意:N个城市形成一棵树,相邻城市之间的距离是1,问访问K个城市的最短路程是多少,共有M次询问(1 <= N, M <= 100000, 1 <= K <= N)。

【思路】

访问K个城市的路线:





可以发现它由一条主线和若干支线构成,并且主线上的边只用访问一次,而支线上的边必须且只用访问两次。而题目给定的是一棵树,那么访问K的城市就必须且仅需要走K-1条边。总边数是固定的,我们只需要保证主线最长即可,所以就是在树中找最长链。

【找最长链】树形dp,dp[i]表示他的子树的最大深度。选一个树根开始访问,每次访问完根节点的子树都要找出子树中深度最深的两个,把他们加起来更新最长链长度。并且留下最深的深度+1当作根节点的深度。

#include
#include
#include
#include
#include
#include
#define MID(x,y) ((x+y)/2)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN = 200005;
struct node{
int u, v;
int next;
}arc[MAXN];
int en, head[MAXN];
void init(){
en = 0;
mem(head, -1);
}
void insert(int u, int v){
arc[en].u = u;
arc[en].v = v;
arc[en].next = head[u];
head[u] = en ++;
}
int dp[MAXN];
int maxlen;
bool vis[MAXN];
void dfs(int u){
vis[u] = 1;
int max1 = 0, max2 = 0;
int num = 0;
for (int i = head[u]; i != -1; i = arc[i].next){
int v = arc[i].v;
if (!vis[v]){
num ++;
dfs(v);
if (dp[v] > max1){
max2 = max1;
max1 = dp[v];
}
else{
if (dp[v] > max2){
max2 = dp[v];
}
}
}
}
if (0 == num){
dp[u] = 0;
}
else{
if (num == 1)
maxlen = max(maxlen, max1+1);
else
maxlen = max(maxlen, max1+max2+2);
dp[u] = max1 + 1;
}
return ;
}
int main(){
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
int t;
scanf("%d", &t);
while(t --){
init();
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0; i < n - 1; i ++){
int u, v;
scanf("%d %d", &u, &v);
insert(u, v);
insert(v, u);
}
mem(vis, 0);
mem(dp, 0);
maxlen = 0;
dfs(1);
for (int i = 0; i < m; i ++){
int tmp;
scanf("%d", &tmp);
if (tmp - 1 <= maxlen){
printf("%d\n", tmp - 1);
}
else{
printf("%d\n", maxlen + 2*(tmp-1-maxlen));
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: