『树的直径』两次dfs求树的直径

学习树的直径前提须知

树的直径 是一棵树的某两个最深的叶子节点的连线,多用于与图论算法嵌套考

算法内容

竞赛需要用到的点

1、很简单的算法,不会单独考,学习和熟练使用它的多种情况

树的直径略讲

很简单,两次dfs

至于为什么,可以画图模拟一下,因为一次dfs必然会在一棵子树或者根节点上,每次dfs必然找到一棵子树的最深的叶子节点,那么第二次dfs必然找到另外一棵子树的叶子节点,这两点的唯一路径就是整棵树的直径。由这个定理我们又可以得到,树的直径不止一条

代码如下(参考PT07Z - Longest path in a tree)

//#define fre yes

#include <cstdio>
#include <cstring>

const int N = 10005;
int head[N << 1], to[N << 1], ver[N << 1];
int d[N];
bool Vis[N];

int tot;
void addedge(int x, int y) {
    ver[tot] = y;
    to[tot] = head[x];
    head[x] = tot++;
}

void dfs(int u) {
    Vis[u] = true;
    for (int i = head[u]; ~i; i = to[i]) {
        int v = ver[i];
        if(!Vis[v]) {
            d[v] = d[u] + 1;
            dfs(v);
        }
    }
}

int diameter(int n) {
    int st = 1, mx = -1e9;

    dfs(st);
    for (int i = 1; i <= n; i++) {
        if(d[i] > mx) {
            mx = d[i];
            st = i;
        }
    }

    memset(d, 0, sizeof(d));
    memset(Vis, false, sizeof(Vis));
    dfs(st);

    mx = -1e9;
    for (int i = 1; i <= n; i++) {
        if(d[i] > mx) {
            mx = d[i];
        }
    } return mx;
}

int main() {
    memset(head, -1, sizeof(head));
    static int n;
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d %d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }

    printf("%d
",diameter(n));
    return 0;
}

那么也就会存在另一个问题,让你输出你找的两个节点的最短路径

挺智障的问题,可以在更新完后得到两个节点来搞,也可以在更新时来搞 前者时间消耗多一点,后者空间消耗多一下 看自己喜好 这里就不放代码了

原文地址:https://www.cnblogs.com/Nicoppa/p/11510184.html