树的直径

两次dfs

时间复杂度\(O(n)\)

先从任意移动p出发,找离他最远的点q,在从q点出发,找离他最远的点w,w到q的距离就是树的直径

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e6 + 5;
struct Edge{
    int to,next,w;
}e[maxn << 1];
int head[maxn],tot;
void add(int u,int v,int w){
    e[++tot].to = v;
  	e[tot].w = w;
    e[tot].next = head[u];
    head[u] = tot;
}
int q;//最远的点
int maxdis = 0;
void dfs(int u,int fa,int dis){
    if(maxdis < dis){
        q = u;
        maxdis = dis;
    }
    for(int i = head[u]; i; i = e[i].next){
        int v = e[i].to;
        if(v != fa)dfs(v,u,dis+e[i].w);
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--){
        int u,v,w;
       	scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    dfs(1,0,1);
    maxdis = 0;
    dfs(q,0,1);
    printf("%d\n",maxdis);
    return 0;
}

树形dp

时间复杂度\(O(n)\)

定义

d[x] 以x为根的子树中,与x最远的结点到x的距离

f[x] 经过点x的所有链中最长一条的长度

edge(u,v) 从结点u到结点v的路径长度

  1. 从叶子结点开始向上合并,对于每一个结点x的d[x],可以通过枚举x的每条边,然后通过转移方程:

\(d[x] = max(d[v_{i}] + edge(x,v_{i}),d[x])\)

  1. 然后对于f[x],若设\(v_{1},v_{2}\)分别为从结点x出发的两个子结点结点,我们可以得到,结果x的最长链是由\((x,v_{1})\)\((x,v_{2})\)组成的。所以在求d[x]时,根据状态转移方程:

\(f[x] = max(d[v_{1}] + d[v_{2}] + edge(x,v_{1}) + edge(x,v_{2}),f[x])\)

但没必要去枚举\(v_{i},v_{j}\)

因为在求d[x]时已经求了一个x到达的最远距离,然后在进行求f[x]时,只需要用\(d[x] + d[v] + edge(x,v)\)即可,如果\(d[x]\)是从\(v_{1}\)出发到达的最长距离,那么\(d[v] + edge(x,v)\)就是从\(v_{2}\)出发到达的最长距离,然后把两个加上即可

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e5 + 5;
struct Edge{
    int to,next,w;
}e[maxn << 1];
int d[maxn],head[maxn],tot;
void add(int u,int v,int w){
    e[++tot].to = v;
    e[tot].w = w;
    e[tot].next = head[u];
    head[u] = tot;
}
int ans = 0;
void DP(int now,int fa){
    for(int i = head[now]; i; i = e[i].next){
        int v = e[i].to;
        if(v == fa)continue;
        DP(v,now);
        ans = max(ans,d[now] + d[v] + e[i].w);
        d[now] = max(d[now],d[v] + e[i].w);
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    while(m--){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    DP(1,0);
    printf("%d\n",ans);
    return 0;
}

posted @ 2020-02-18 13:29  Emcikem  阅读(136)  评论(0编辑  收藏  举报