AcWing 1072 树的最长路径

题目描述:

给定一棵树,树中包含 n个结点(编号1~n)和 n−1 条无向边,每条边都有一个权值。

现在请你找到树中的一条最长路径。

换句话说,要找到一条路径,使得使得路径两端的点的距离最远。

注意:路径中可以只包含一个点。

输入格式

第一行包含整数 n。

接下来 n−1行,每行包含三个整数 ai,bi,ci,表示点 ai和 bi 之间存在一条权值为 ci 的边。

输出格式

输出一个整数,表示树的最长路径的长度。

数据范围

1≤n≤10000
1≤ai,bi≤n,
−10^5≤ci≤10^5

输入样例:

6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7

输出样例:

22

分析:

首先分析下普通的树的直径的问题,即给定一棵边权都是1的树,求树中两个节点之间最长的路径。一般采用两次BFS,第一次随便取一个节点做次BFS,找到离该点最远的点u,再对u做次BFS,找到离u最远的点v,uv的长度就是树的直径。需要证明这种做法为什么是对的。

如图所示,设xy是树的最长的路径,第一种情况,任取一点o,u是离o最远的一点,下面证明u一定是树的某条最长路径的端点。这种情况下已知的最长路径xy与ou是不相交的,由于u是树上离o最远的点,所以op + pu = ou >= op + pq + qy,即pu >= pq + qy,故pu + pq >= qy,pu + pq + qx >= qy + qx,即upqx构成的路径长度不小于之前设定的最长路径xy,故u是某条最长路径的端点。第二种情况,ou与某条最长路径xy相交于节点p,u离o最远,故op + pu >= op + py,即pu >= py,pu + px >= py + px,故upx构成的也是一条最长路径,u是树的某条最长路径的端点。综上所述,一次BFS找到的点u一定是树的某条最长路径的端点,在做次BFS找到的里u最远的点便是该路径的另一个端点了,问题得证。

树的所有边权相等只是问题的一个特殊情况。本题中树的边权可以不等,甚至可以是负数,需要另谋他法。老实说,y总对这题的讲解表述有点模糊,并没有说的特别清楚,我觉得与其非要说是树形dp问题,倒不如说是一个普通树的DFS问题。由于普通树没有规定哪个节点是根结点,所以可以任选一点作为根节点,从根节点起做dfs,找到离根节点最远的点。

如图所示,任意一棵树,树的最长路径要么经过根节点,要么不经过根节点。经过根节点时,只需要找到根节点孩子节点中最长的路径和次长的路径,这里最长路径和次长路径一定位于根节点的不同子树中,所以连接起来就是最长的路径了,比如上图的蓝色路径。如果最长路径不经过根节点呢?比如上图的红色路径,则一定经过树的某个节点,说清楚点就是,树的最长路径中一定有个最高的节点,比如红色路径中最高的节点就是根节点的左孩子节点,我们从根节点出发做DFS时,不仅求出了到根结点的最长路径和次长路径,同时递归的求出了任意一个节点到其子树的最长路径和次长路径,既然树的最长路径的最高的节点一定存在,那么我们做DFS时比较下以每个节点为根的子树中最长路径长度加上次长路径长度,取其最大值就是树的最长路径了。

注意:由于本题的树是无向的,所以在做DFS是遇见遍历到某节点的根节点时需要跳过。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 10005,M = 20005;
int n,h[N],e[M],ne[M],w[M],idx,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 fa){
    int d1 = 0,d2 = 0;
    for(int i = h[u];~i;i=ne[i]){
        int j = e[i];
        if(j == fa) continue;
        int d = dfs(j,u) + w[i];
        if(d > d1)  d2 = d1,d1 = d;
        else if(d > d2) d2 = d;
    }
    ans = max(ans,d1 + d2);
    return d1;
}
int main(){
    cin>>n;
    int a,b,c;
    memset(h,-1,sizeof h);
    for(int i = 0;i < n - 1;i++){
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    dfs(1,-1);
    cout<<ans<<endl;
    return 0;
}
发布了311 篇原创文章 · 获赞 31 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_30277239/article/details/104396460
今日推荐