zoukankan      html  css  js  c++  java
  • 树的直径

    树的直径

    定义:树的直径为树中最远的两个节点的距离之和。在求树的直径时一般有两种方法:树形dp或则两个BFS(DFS也可以)。

    1.树形dp求解树的直径

    思路:由树的直径定义可知:其树形dp的状态转移方程为:

    [D[x]=max(D[y_i]+Edge(x_i,y_i)) ]

    其中D[x]表示从节点x出发走向以x为根的子树,能够到达的最远距离。

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn=1e5+10;
    struct node
    {
        int nex,to,val;
    }edge[maxn];
    int head[maxn],dis[maxn],v[maxn],n,s,res=0,tot=0;
    void add(int from,int to,int val)
    {
        edge[++tot].to=to;
        edge[tot].val=val;
        edge[tot].nex=head[from];
        head[from]=tot;
    }
    void dp(int x)
    {
        v[x]=1;
        for(int i=head[x];i!=-1;i=edge[i].nex)
        {
            int y=edge[i].to;
            if(v[y]) continue;
            dp(y);
            res=max(res,dis[x]+dis[y]+edge[i].val);
            dis[x]=max(dis[x],dis[y]+edge[i].val);
        }
    }
    
    int main()
    {
        scanf("%d%d",&n,&s);
        memset(head,-1,sizeof(head));
        for(int i=1;i<n;++i)
        {
            int a,b,val;
            scanf("%d%d%d",&a,&b,&val);
            add(a,b,val);
            add(b,a,val);
        }
        dp(s);
        printf("%d
    ",res);
        system("pause");
    }
    

    2.两次BFS求解树的直径

    两次DFS或者BFS也可以求得树的直径,并且更容易的计算出直径上的具体结点。

    3.两次DFS求解树的直径

    如需求具体方案,只需在第二次dfs的时候记录一下即可,show code:

    #include<bits/stdc++.h>
    
    using namespace std;
    const int maxn=1e5+10;
    const int inf=0x3f3f3f3f;
    struct node
    {
        int nex,to,val;
    }edge[maxn];
    int head[maxn],tot=0,n,m,dis[maxn],res;
    bool v[maxn];
    int start,ed;
    inline void add(int from,int to,int val) 
    {
        edge[++tot].to = to;
        edge[tot].val=val;
        edge[tot].nex=head[from];
        head[from]=tot;
    }
    void dfs(int x)
    {
        v[x]=1;
        for(int i=head[x];i!=-1;i=edge[i].nex){
            int y=edge[i].to;
            if(v[y])    continue;
            dis[y]=dis[x]+edge[i].val;
            dfs(y);
        }
    }
    
    int main()
    {
        memset(v,0,sizeof(v));
        memset(head,-1,sizeof(head));
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;++i){
            int a,b,val;
            scanf("%d %d %d",&a,&b,&val);
            add(a,b,val);
            add(b,a,val);
        }
        for(int i=1;i<=n;++i)
            dis[i]=(i==1)?0:inf;
        dfs(1);                     //找到树的一个端点
        res=0;
        for(int i=1;i<=n;++i) 
            if(dis[i]>res&&dis[i]!=inf){
                res=dis[i];        //找到1的一个最远的端点,start确定
                start=i;
            }
        memset(v, 0, sizeof(v));        //注意重新初始化
        for(int i=1;i<=n;++i)
            dis[i]=(i==start)?0:inf;
        dfs(start);
        res=0;                        //找到离端点最远的结点,距离即为直径
        for(int i=1;i<=n;++i) 
            if(dis[i]>res&&dis[i]!=inf){
                res=dis[i];
                ed=i;
            }
        printf("%d
    ",res);
    }
    
  • 相关阅读:
    如何运用领域驱动设计
    如何运用领域驱动设计
    linq Select与SelectMany的区别
    linq GroupBy 多字段分组
    Enumerable<T>的GroupJoin 方法和Join的用法和区别
    使用vscode搭建vue开发环境
    C# Windows服务发布生成步骤
    C#使用表驱动算法实现多层if或者switch语句重构
    记一次服务器重启后应用程序启动出错
    项目中的NLog日志记录
  • 原文地址:https://www.cnblogs.com/StungYep/p/12252201.html
Copyright © 2011-2022 走看看