求树的直径

Posted -ackerman

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求树的直径相关的知识,希望对你有一定的参考价值。

前言

树的直径指树上距离最远的两点间的距离,它在树上问题上有许多应用,往往通过树的直径的性质可以将一个高时间复杂度的解法变为线性求解。

 

树型DP求解树的直径的方法:复杂度 O(N)

DP求直径的方法是对于每个点记录这个点子树中的最长链及与最长链处于不同子树中的次长链,用每个点的最长链+次长链更新直径,然后再将最长链上传到父节点更新父节点的最长链或次长链。这种求法适用于所有求树的直径的情况。

 

我们用 f1[x] 代表 x 为根的子树最长链,f2[x] 代表 x 为根的子树次长链

每次先更新最长,再更新次长

 

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <math.h>
#include <cstdio>
#include <iomanip>
#include <time.h>
#include <bitset>
#include <cmath>

#define LL long long
#define INF 0x3f3f3f3f
#define ls nod<<1
#define rs (nod<<1)+1

const double eps = 1e-10;
const int maxn = 1e6 + 10;
const LL mod = 1e9 + 7;

int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;}
using namespace std;

struct edge {
    int v,w,nxt;
}e[maxn];

int head[maxn],f1[maxn],f2[maxn];
int cnt,ans;
void add_edge(int u,int v,int w) {
    e[++cnt].nxt = head[u];
    e[cnt].w = w;
    e[cnt].v = v;
    head[u] = cnt;
}


void dfs(int u,int f) {
    f1[u] = f2[u] = 0;
    for (int i = head[u];~i;i = e[i].nxt) {
        int v = e[i].v;
        if (v == f)
            continue;
        dfs(v,u);
        if (f1[u] < f1[v] + e[i].w) {
            f2[u] = f1[u];
            f1[u] = f1[v] + e[i].w;
        }
        else if (f2[u] < f1[v] + e[i].w)
            f2[u] = f1[v] + e[i].w;
    }
    ans = max(ans,f1[u]+f2[u]);
}

int main() {
    //freopen("../in.txt","r",stdin);
    memset(f1,0,sizeof(f1));
    memset(f2,0, sizeof(f2));
    memset(head,-1, sizeof(head));
    cnt = 0,ans = 0;
    int u,v,w;
    while (~scanf("%d%d%d",&u,&v,&w)) {
        add_edge(u,v,w);
        add_edge(v,u,w);
    }
    dfs(1,0);
    printf("%d
",ans);
    return 0;
}

 

以上是关于求树的直径的主要内容,如果未能解决你的问题,请参考以下文章

求树的直径+并查集(bfs,dfs都可以)hdu4514

树上子链(树形dp求树的直径)

HDU 4612 Warm up(双连通分量缩点+求树的直径)

poj:1985:Cow Marathon(求树的直径)

两次bfs求树的直径的正确性

求树的直径