题目来源:click
问树中的节点到树中另一个节点的最远路径。
从一个节点入手分析,树形dp便是找他与子节点,父节点之间的状态。
如果当前节点选择走子节点,可以发现他不会再走父节点,那么他只能一直走下去,走的都是子节点。这个可以先写一个dfs1()来表示,从下至上。
如果当前节点选择走父节点,那么之后它又可以选择走父节点的子节点或者父节点的父节点。用dfs2()来表示,从上至下。
因为考虑到走父节点仍然会走子节点,先进行dfs1()。
具体可见代码。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<map>
#include<algorithm>
#include<queue>
#define MAX_len 50100*4
using namespace std;
typedef long long ll;
int n;
struct A{
int v,w;
};
vector<A>hh[10011];
bool vis[10011];
int fa[10011];
int dp[10011][2];// 0表示走儿子结点 1表示走父亲节点
int dfs1(int root)//表示走的是儿子结点,一旦走了儿子结点的话就不可能再走父亲节点,是一直往下走的,所以dfs一直到看做1为根到叶子节点,从下往上做dp
{
vis[root]=true;
dp[root][0]=0;
for(int i=0;i<hh[root].size();i++)
{
int v=hh[root][i].v;
if(vis[v])
continue;
dp[root][0]=max(dp[root][0],dfs1(v)+hh[root][i].w);
}
return dp[root][0];
}
void dfs2(int root,int f)//如果走的是父亲结点,则有可能走父亲的其他子节点,从上往下的dp
{
//vis[root]=true;
int t=0;
dp[root][1]=dp[f][1];
for(int i=0;i<hh[f].size();i++)
{
int v=hh[f][i].v;
if(v==fa[f])
continue;
if(v==root)
t=hh[f][i].w;
else
dp[root][1]=max(dp[root][1],dp[v][0]+hh[f][i].w);
}
dp[root][1]+=t;
for(int i=0;i<hh[root].size();i++)
if(hh[root][i].v!=f)
dfs2(hh[root][i].v,root);
}
int main()
{
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
memset(vis,false,sizeof(vis));
int i,j,k;
for(i=1;i<=n;i++)
hh[i].clear();
for(i=2;i<=n;i++)
{
int v,w;
scanf("%d %d",&v,&w);
fa[i]=v;
hh[v].push_back((A){i,w});
hh[i].push_back((A){v,w});
}
dfs1(1);//就直接以1为根结点进行dp
dfs2(1,0);
for(i=1;i<=n;i++)
printf("%d\n",max(dp[i][0],dp[i][1]));
}
return 0;
}