Computer(HDU2196)——树形dp的那些事

让我们先附上原题链接

这个题目的题意翻译过来差不多就是求树上每一个节点在树上的最远距离。其实这题目有两个做法
一个是求树的直径,一个是用树形dp,但是这里只说树形dp的方法,求直径的方法思路还是比较简单的。

对于树形dp我们有以下的思路,对于一个节点root在树上的最长路径,有两种可能。一:此路径在以root为根节点的子树上,二:此路径经过其父节点。所以我们可以将树设为以1为根,然后进行两次dfs,第一次求出以x为起点并在其子树内的最长路径以及次长路径。之后第二次dfs求出经过x父节点的最长路径。思路就是这样了。接下来贴代码。

#include<bits/stdc++.h>
using namespace std;
struct nob{
	int sta,ed,val,jump;
}a[20005];
int n,jump[10005],num,fa[10005],dp[10005][3];
//dp[x][0]表示子树内最长路径,dp[x][1]表示子树内次长路径,dp[x][2]表示经过父节点的最长路径 
void add(int sta,int ed,int val){
	num++;
	a[num].sta=sta;
	a[num].ed=ed;
	a[num].val=val;
	a[num].jump=jump[sta];
	jump[sta]=num;
}
void dfs1(int pos){
	dp[pos][0]=0;
	dp[pos][1]=0;
	dp[pos][2]=0;
	for (int i=jump[pos]; i; i=a[i].jump){
		dfs1(a[i].ed);
		if (dp[a[i].ed][0]+a[i].val>=dp[pos][1]){
			dp[pos][1]=dp[a[i].ed][0]+a[i].val;
			if (dp[pos][0]<dp[pos][1]) swap(dp[pos][0],dp[pos][1]);
		}
	}
}
void dfs(int pos){
	for (int i=jump[pos]; i; i=a[i].jump){
		if (dp[pos][0]==dp[a[i].ed][0]+a[i].val){
			dp[a[i].ed][2]=max(dp[pos][2],dp[pos][1])+a[i].val;
		}
		else{
			dp[a[i].ed][2]=max(dp[pos][2],dp[pos][0])+a[i].val;
		}
		dfs(a[i].ed);
	}
}
int main(){
	while(~scanf("%d",&n)){
		num=0;
		memset(jump,0,sizeof(jump));
		for (int i=2,x,y; i<=n; i++){
			scanf("%d%d",&x,&y);
			add(x,i,y);
		}
		dfs1(1);
		dfs(1);
		for (int i=1; i<=n; i++){
			printf("%d\n",max(dp[i][0],dp[i][2]));
		}	
	}
	
	return 0;
}
posted @ 2017-10-29 15:56 |斗蜂| 阅读(...) 评论(...) 编辑 收藏