题意
一颗树有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;
}