HDU_2196 Computer (树型dp)

  纠结的问题。做了两天,还是在拜读大牛代码的情况下ac的。好好谢谢总结吧。

  诸位大牛的思路是两次dfs。前提:建树的时候按无向边从上往下建。第一次dfs是搜出一个根结点到其他结点的最长路径和次长路径(次长路径不是最长路径的子路径,也就是说不在同一条路上。)

  一个结点到其他结点的最长路径怎么得到?1、可能是从这个结点往下取到最长路径。2、可能是从这个结点的父结点上选去另一条路径。

  当情况一时:第一次dfs所得的最长路径就是要求的结果。当情况二时:第一次dfs所得的次长路径就是所求结果。

  另外,因为是无向边建树,所以第一次dfs从下往上搜,第二次dfs从上往下搜。

  具体实现:定义dp[i]表示i到其他结点的最长路径。 f[i]表示从i结点到他的子结点的最长路径 l[i]表示i到其子结点的次长路径。 dir[i]表示最长路径所在的方向,防止最长路径跟次长路径重复。

核心代码:

void dfs_0(int r) {
if(f[r]) return ;
int len = g[r].size();
if(len == 0) return ;
int i, max = -1, flag = -1, flag1 = -1, c;
for(i = 0; i < len; i++) {
c = g[r][i].c;
dfs_0(c);
if(f[c] + g[r][i].val > max) {
max = f[c] + g[r][i].val;
flag = i;
}
}
f[r] = max;
dir[r] = flag;
max = -1;
for(i = 0; i < len; i++) {
c = g[r][i].c;
if(f[c] + g[r][i].val > max && i != flag) {
max = f[c] + g[r][i].val;
flag1 = i;
}
}
if(flag1 != -1) l[r] = max;
}

void dfs_1(int r) {
int i, len, c;
len = g[r].size();
for(i = 0; i < len; i++) {
c = g[r][i].c;
if(i == dir[r])
dp[c] = max(dp[r], l[r]) + g[r][i].val;
else
dp[c] = max(dp[r], f[r]) + g[r][i].val;
dfs_1(c);
}
}

ps:因为可能出现整颗树只有一条边的情况,所以输出结果时取f[i] 和dp[i]的最大。

posted @ 2012-01-07 17:13  AC_Von  阅读(379)  评论(0编辑  收藏  举报