题意:求树中任意两点的最长距离;
思路:树形dp,这个也是入门题,不过稍难一些,因为状态转移时需要从父亲或儿子中转移,YY了很久也没什么思路,主要是不知道怎么从父亲中状态转移,看了下别人的分析。。原来需要用到两次dfs,还要维护儿子中最长距离和次最长距离(用set,或vector然后排序),涨姿势了。。千辛万苦总算A了。。推荐一篇比较好的分析,认真看下就懂了(http://hi.baidu.com/avovkozpikgprur/item/70cf22d3a440421c20e2505c)。
还有一个地方需要注意的是,如果建的边是双向,那么edge[]数组务必开成点数的2倍,有一题就因为这个错了好几次,还以为是算法错了、、
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10010;
struct Node {
int e, len, next;
} edge[N];
//dp[N][0]到儿子最长距离,dp[N][1]到儿子次长距离,dp[N][2]到父亲最长距离
struct go {
int val, idx;
} dp[N][3], p;
int head[N], cnt;
void addedge(int a, int b, int w) {
edge[cnt].e = b;
edge[cnt].len = w;
edge[cnt].next = head[a];
head[a] = cnt++;
}
void dfs_son(int u, int fa) {//找儿子中的最长距离,和次长距离
for (int i = head[u]; i != -1; i = edge[i].next){
int e = edge[i].e, weight = edge[i].len;
if (e == fa)
continue;
dfs_son(e, u);
p.val = dp[e][0].val + weight, p.idx = e;
if(p.val > dp[u][0].val){
dp[u][1] = dp[u][0];
dp[u][0] = p;
} else if(p.val > dp[u][1].val)
dp[u][1] = p;
}
}
void dfs_father(int u, int fa) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int e = edge[i].e, weight = edge[i].len;
if (e == fa)
continue;
int fir_val = dp[u][0].val, fir_idx = dp[u][0].idx;
int sec_val = dp[u][1].val;
if (fir_idx == e)
dp[e][2].val = max(dp[e][2].val, sec_val + weight);
else if (fir_idx != e)
dp[e][2].val = max(dp[e][2].val, fir_val + weight);
dp[e][2].val = max(dp[u][2].val + weight, dp[e][2].val);
dfs_father(e, u);
}
}
int main() {
int n, a, b, i;
scanf("%d", &n);
memset(dp, 0, sizeof dp);
memset(head, -1, sizeof(head));
for (i = 2; i <= n; i++) {
scanf("%d%d", &a, &b);
addedge(a, i, b);
}
dfs_son(1, -1);
dfs_father(1, -1);
for (i = 1; i <= n; i++)
printf("%d\n", max(dp[i][0].val, dp[i][2].val));
return 0;
}