HDU2196:树形DP

HDU2196

题解

  • 在一棵树上,求每个结点能到达的最远距离。
  • 设结点到子树的最大距离为深度。那么结点能到达的最远距离可能为深度(1),也可能为经过先到父结点再到兄弟结点的子树(2),或者直接一直往上走到另一边(3)。
  • 如果u的父节点到子树的最大距离经过u,那么u的最远距离为max(1,2,3)。
  • 如果u的父节点到子树的最大距离不经过u,那么max(2,3)。
  • 先自底向上dfs一遍。记录最大距离和相应的子节点,记录次大距离(2好方案所需)。
  • 在自顶向下dfs一遍。dp[0][i]表示最大距离,dp[1][i]表示次大距离,dp[2][i]表示2和3号方案的最大的距离。
  • 注意dp过程中先记录2和3的最大值,最后再和1取最大。否则出错,因为包含了到子树的最大距离了。

代码

#include <bits/stdc++.h>
using namespace std;
int const N = 10000 + 10;
struct Node
{
	int to,val;
	Node(){};
	Node(int to,int val):to(to),val(val){}
};
vector<Node>G[N];
int n,dp[3][N],id[N];
void dfs1(int u,int fa){
	for(int i=0;i<G[u].size();i++){   //找最长
		Node v = G[u][i];
		if(v.to == fa)	continue;
		dfs1(v.to,u);	
		if(dp[0][u] < dp[0][v.to] + v.val){
			dp[0][u] = dp[0][v.to] + v.val;
			id[u] = v.to;
		}
	}
	for(int i=0;i<G[u].size();i++){  //次短路
		Node v = G[u][i];
		if(v.to == fa)	continue;
		if(v.to == id[u])	continue;   //在另外一个子节点上找
		dp[1][u] = max(dp[1][u],dp[0][v.to] + v.val);
	}
}
void dfs2(int u,int fa){
	for(int i=0;i<G[u].size();i++){
		Node v = G[u][i];
		if(v.to == fa)	continue;
		if(v.to == id[u]){   //u的最长路经过子节点
			dp[2][v.to] = max(dp[2][u],dp[1][u]) + v.val;
		}else{
			dp[2][v.to] = max(dp[2][u],dp[0][u]) + v.val;
		}
		dfs2(v.to,u);
	}
}	
int main(){
	while(~scanf("%d",&n)){
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++)	G[i].clear();
		for(int i=2;i<=n;i++){
			int u,len;
			scanf("%d%d",&u,&len);
			G[i].push_back(Node(u,len));
			G[u].push_back(Node(i,len));
		}
		dfs1(1,-1);
		dfs2(1,-1);
		for(int i=1;i<=n;i++)	printf("%d\n",max(dp[0][i],dp[2][i]));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/89302369