• 树的直径


    两次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
    ",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
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    【tyvj1952】easy
    【noip2005】篝火晚会
    BZOJ4818: [Sdoi2017]序列计数
    BZOJ2436: [Noi2011]Noi嘉年华
    BZOJ4826: [Hnoi2017]影魔
    BZOJ4540: [Hnoi2016]序列
    BZOJ4827: [Hnoi2017]礼物
    BZOJ3527: [Zjoi2014]力
    BZOJ4407: 于神之怒加强版
    BZOJ1854: [Scoi2010]游戏
  • 原文地址:https://www.cnblogs.com/Emcikem/p/12325863.html
Copyright © 2020-2023  润新知