C++ --- tree DP --- the longest path of the tree (a daily algorithm 2023.5.4)

Note:
This title is an approximate title of "DFS Depth-First Traversal of Trees and Graphs—the Center of Gravity of Trees" , and it also involves the operation of singly linked lists simulating adjacency list storage graphs. It is recommended to understand that article first.

Title:
Given a tree, the tree contains n nodes (numbered 1~n) and n−1 undirected edges, and each edge has a weight.
Now please find the longest path in the tree.
In other words, find a path such that the points at both ends of the path are farthest apart.
Note: A path can contain only one point.

Input Format
The first line contains the integer n.
Next n−1 lines, each line contains three integers ai, bi, ci, which means there is an edge with weight ci between points ai and bi.

Output Format
Output an integer representing the length of the longest path in the tree.

Data range
1≤n≤10000,
1≤ai,bi≤n,
−1e5≤ci≤1e5

输入:
6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7
输出:
22
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 10010, M = N*2;
int n, ans;                              //ans存储最终答案
int h[N], e[M], ne[M], w[M], idx = 0;     //单链表模拟邻接表

//邻接表增加一条边
void add(int a, int b, int c) {
    
    
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx++;
}

//dfs数位dp,u是当前节点,f是当前节点的上一个节点(父节点)
int dfs(int u, int f) {
    
    
    int dist = 0;  //从当前点往下走的最大长度
    int d1 = 0, d2 = 0;   //表示挂在当前点上的最长路径d1和次长距离d2

    //枚举当前点i能到达的所有子节点j(遍历单链表)
    for (int i = h[u]; i!=-1; i=ne[i]) {
    
    
        int j = e[i];
        if (j == f) continue;   //由于是无向边,从a到b和从b到a都能走,但我们希望只能向下走,所以不能走回父节点

        int d = dfs(j, u) + w[i];   //子节点j往下走的最大长度 + j到i的边权
        dist = max(dist, d);

        //两种情况: 1.如果d大于等于d1,原本的最长路径就变为了次长路径,再把d存为最长路径 / 2.如果d不大于d1,但大于d2,直接更新即可
        if (d >= d1) {
    
    d2 = d1, d1 = d;}
        else if (d > d2) {
    
    d2 = d;}
    }

    ans = max(ans, d1+d2);    //d1+d2得到的就是穿过当前这个点的最长路径,因为一条最长向下的路 + 一条次长向下的路,合起来就是最长的路
    return dist;
}

int main() {
    
    
    //读入
    cin >> n;
    memset(h, -1, sizeof h);  //所有链头都指向-1即可
    for (int i = 0; i<n-1; i++) {
    
      //n-1条无向边
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c); add(b, a, c);
    }

    dfs(1, -1);     //初始父节点随便设个不存在的就行
    cout << ans;

    return 0;
}

Idea: The
overall idea is not difficult. First of all, the tree can be "picked up", that is, one point can be randomly selected as the root node, and the remaining points are
extended downwards (have you ever seen a binary tree? It looks similar , but can have multiple child nodes).

The "highest" nodes of all paths can be enumerated through dfs. Suppose the current path is 1-2-3 and the highest node is 2.
How to find the longest path among all paths with the highest point of 2?
Find all slave nodes 2 The longest path and the second longest path in the downward extension are the answer.
dfs returns the longest path extended downward from the current node, so if there are multiple child nodes, you can directly Just compare the returned results of dfs+w[i,j].
Please add a picture description

There are also situations encountered when updating the longest and second-longest paths:
1. If the new path d is greater than or equal to d1, the original longest path becomes the second-longest path, and then save d as the longest path
2. If d is not greater than d1, but greater than d2, just update it directly

If it is helpful, please give a free like~ Someone watching is the motivation to support me to write down!

Disclaimer:
The source of the algorithm idea is Mr. Y. For details, please refer to https://www.acwing.com/
This article is only used for learning records and exchanges

Guess you like

Origin blog.csdn.net/SRestia/article/details/130492351