经典的树形dp
hdu2196,非常经典的树形dp,由于太久没写居然忘了怎么换根。于是水一篇博客加深加深印象。
其实懂了之后思路就有了,主要在于换根,因为无根树,我们先选取1为根,后面的根都可以通过公式换出来。
所以,当我们得到了第一棵树的最长子树路径,这时候第一棵树的答案其实就出来了,然后我们就需要思考,第二棵树,就相当于1的子树,我们假定是2,2的最长路就为2的最长子树加上1的次长子树或者1到2的路径长,即2的父亲路径。
自己画的图(丑得离谱)
//
// Created by SANZONG on 2020/10/23.
//
#include "cstdio"
#include "cstring"
#include "iostream"
#include "algorithm"
#include "map"
using namespace std;
int cnt = 0;
const int N = 10020;
int head[N];
struct node {
int to, next, w;
} com[N * 2];
int dp[N][3];
int add(int u, int v, int w) {
com[++cnt].next = head[u];
com[cnt].to = v;
head[u] = cnt;
com[cnt].w = w;
}
//注意只以1为根,向上遍历,得到1这个节点开始的最长与次长
//下面所有节点最长路径可能由这个点向下的最长路+上面的路径长度
int dfs(int u, int fa) {
for (int i = head[u]; i; i = com[i].next) {
int v = com[i].to;
if (v == fa)
continue;
dfs(v, u);
if(dp[u][0] < dp[v][0] + com[i].w)
{
dp[u][1] = dp[u][0];
dp[u][0] = dp[v][0] + com[i].w;
} else {
dp[u][1] = max(dp[u][1],dp[v][0] + com[i].w);
}
}
}
void dfs2(int u,int fa)
{
for (int i = head[u]; i ; i = com[i].next) {
int v = com[i].to;
if (v == fa) return;
if (dp[v][0] + com[i].w == dp[u][0]) //在最长路上
dp[v][2] = max(dp[u][1],dp[u][2]) + com[i].w;
else
dp[v][2] = max(dp[u][0],dp[u][2]) + com[i].w;
dfs2(v,u);
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int N;
while (cin >> N) {
cnt = 0;
memset(head,0,sizeof(head));
for (int i = 2; i <= N; ++i) {
int v, w;
cin >> v >> w;
add(i, v, w);
add(v, i, w);
}
memset(dp, 0, sizeof(dp));
dfs(1, 0);
dfs2(1,0);
for (int i = 1; i <= N; i++) {
cout << max(dp[i][0],dp[i][2]) << endl;
}
}
}