树形DP,树的最长路径(直径)

题意

一颗树有n个点,并且有n-1条无向边,每条边都有边权,问这颗树的最长路径是多少。

思路

最长路径中的点的类型有两种,一种是这个点为最长路径的端点,另一种是这个点是最长路径的中间节点。因为是无向树,所以我们可以以任意一个点为根节点,所以当我们确认根节点后,我们可以计算出所有点的向下走的最长距离和次长距离,次长距离和最长距离加起来就是以这个点为悬挂点的最长路径(悬挂点:以这个点为最高点),然后不断更新树的最长路径。我们不用考虑向上的走的方式,因为如果当前点为数的直径中的节点,并且下一个点在上面的话,我们这条直径就会在计算上一层的时候进行计算了,也就是一条直径上的所有点的都是等价的。而如果这个节点无法向下走,也就是为最长路径的端点,也不影响,因为我们也会在上面的节点中计算经过这个点的直径。
所以我们就用dfs的方式算出分别以每一个节点为悬挂点的最长路径。我们在dfs的时候还要开个father变量,用来判断是不是当前的点是不是上面的节点,因为我们是无向树,并且要保证当前的点是悬挂点,所以我们要避免判断到上层的节点,否则会重复判断甚至死循环。

具体代码

#include<iostream>
#include<cstring>
using namespace std;

const int N=10010,M=N*2;

int n;
int h[N],e[M],w[M],ne[M],idx;
int ans;

void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}

int dfs(int u,int father)//father用来判断是不是又判断回去了
{
	int dist=0;//表示从当前点往下走的最大距离
	int d1=0,d2=0;//表示从这个点往下走的最长距离和次长距离
	
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		if(j==father) continue;
		int d=dfs(j,u)+w[i];//当前子节点往下走的最长距离,加上当前节点到达子节点的距离
		dist=max(dist,d);//更新这个点向下走的最大距离 
		
		if(d>d1) d2=d1,d1=d;//如果当前的向下走的路径大于最长距离就更新最长距离,和次长距离
		else if(d>d2) d2=d;//如果只大于次长路径,就更新次长距离就好。 
	}
	
	ans=max(ans,d1+d2);//最长直径是最长加次长组成的。
	
	return dist; 
} 

int main()
{
	cin>>n;
	memset(h,-1,sizeof h);
	for(int i=0;i<n-1;i++)
	{
		int a,b,c;
		cin>>a>>b>>c;
		add(a,b,c),add(b,a,c); 
	}
	
	dfs(1,-1);
	
	cout<<ans<<endl;
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值