http://acm.hdu.edu.cn/showproblem.php?pid=2196
#include<iostream>
using namespace std;
#define N 10001
struct node{
int next,v,w;
node(){};
node(int a,int b,int c){
next=a;v=b;w=c;
}
}E[N];
int head[N],NE;
int up[N],down_f[N],down_s[N];
int mark[N];
void init(){
NE=0;
memset(head,-1,sizeof(head));
}
void insert(int u,int v,int w){
E[NE]=node(head[u],v,w);
head[u]=NE++;
}
int dfs(int u){ //从下往上跟新
int M1=-1,M2=-1,id;
bool flag=0;
for(int i=head[u];i!=-1;i=E[i].next){
flag=1;
int v=E[i].v;
int w=dfs(v);
if(w+E[i].w>M1){
M2=M1;
M1=E[i].w+w;
id=i;
}
else if(w+E[i].w==M1)
M2=M1;
else if(w+E[i].w>M2)
M2=w+E[i].w;
}
if(!flag){
down_f[u]=0;
down_s[u]=0;
}
else{
down_f[u]=M1;
mark[u]=id;
down_s[u]=M2;
}
return down_f[u];
}
void dfs2(int u){ //从上往下跟新
for(int i=head[u];i!=-1;i=E[i].next){
int v=E[i].v;
if(i==mark[u])
up[v]=max(up[u],down_s[u])+E[i].w;
else
up[v]=max(up[u],down_f[u])+E[i].w;
dfs2(v);
}
}
int GetInt(){
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
int num=0;
while(ch>='0'&&ch<='9'){
num=num*10+ch-'0';
ch=getchar();
}
return num;
}
int main(void){
int n;
while(~scanf("%d",&n)){
init();
for(int i=2;i<=n;i++){
int u,w;
u=GetInt();
w=GetInt();
insert(u,i,w);
}
dfs(1);
up[1]=0;
dfs2(1);
for(int i=1;i<=n;i++)
printf("%d\n",max(down_f[i],up[i]));
}
}
树形DP啊,很弱,这个经典题,用到的dp数组不止一个
这道题就是给你一颗树,问你树中每个节点到任意节点的最长距离
首先看一下这个最长距离可能由哪些途径来"竞争"! 根节点不用说,就是到最远的叶子节点距离,主要是除了根节点以外的节点
1.对于叶子节点,在图上随意画个树,可以发现,叶子节点的最远距离由它的父亲节点得到,可能是父亲节点往上走,走到根,然后加上根节点到其他叶子节点的最远距离;也有可能是父亲节点往下走,也许这个父亲节点另外一个孩子路径节点特别多,那么这个时候最远距离就是它了。问题在于,只记录一个节点往下的最大距离就够了吗?答案是不行!因为要是你这个最大距离包含着当前点怎么办?这样就重合了,解决的办法就是记录一个次最远距离,当重合的时候,就用这个次最远距离就好了,dfs中就是处理最远距离和次远距离的,同时要记录以当前节点为根的最远距离的编号,用来判断之后是否重合
2.对于非叶子节点,它有可能是往下走,这就是down_f[]中记录的值,也有可能是往上走,跟叶子节点一样
用到三个dp数组,down_f[]记录该节点往下走的最远距离,down_s[]记录次远距离,up[]记录往上走,走到根又往下走的最远距离