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

    学习博客:https://www.cnblogs.com/ywjblog/p/9254997.html

    树的直径
    给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和。树中最远的两个节点之间的距离被称为树的直径,连接这两点的路径被称为树的最长链。后者通常也可称为直径,即直径是一个 
    数值概念,也可代指一条路径
    树的直径通常有两种求法,时间复杂度均为O(n)。我们假设树以N个点N-1条边的无向图形式给出,并存储在邻接表中。

    第一种是dp求法,在这里我只介绍bfs求法:

    两次BFS(DFS)求树的直径
    通过两次BFS或者两次DFS也可以求树的直径,并且更容易计算出直径上的具体节点
    详细地说,这个做法包含两步:
    1.从任意节点出发,通过BFS和DFS对树进行一次遍历,求出与出发点距离最远的节点记为p
    2.从节点p出发,通过BFS或DFS再进行一次遍历,求出与p距离最远的节点,记为q。
    从p到q的路径就是树的一条直径。因为p一定是直径的一端,否则总能找到一条更长的链,与直径的定义矛盾。显然地脑洞一下即可。p为直径的一端,那么自然的,与p最远的q就是直径的另一端。
    在第2步的遍历中,可以记录下来每个点第一次被访问的前驱节点。最后从q递归到p,即可得到直径的具体方案

    下面看一道例题:

    题目链接:https://ac.nowcoder.com/acm/contest/884/A

    链接:https://ac.nowcoder.com/acm/contest/884/A
    来源:牛客网

    meeting
    时间限制:C/C++ 1秒,其他语言2秒
    空间限制:C/C++ 524288K,其他语言1048576K
    64bit IO Format: %lld

    题目描述

    A new city has just been built. There're nnn interesting places numbered by positive numbers from 111 to nnn.
    In order to save resources, only exactly n−1n-1n1 roads are built to connect these nnn interesting places. Each road connects two places and it takes 1 second to travel between the endpoints of any road.
    There is one person in each of the places numbered x1,x2…xkx_1,x_2 ldots x_kx1,x2xk and they've decided to meet at one place to have a meal. They wonder what's the minimal time needed for them to meet in such a place. (The time required is the maximum time for each person to get to that place.)

    输入描述:

    First line two positive integers, n,kn,kn,k - the number of places and persons.
    For each the following n−1n-1n1 lines, there're two integers a,ba,ba,b that stand for a road connecting place aaa and bbb. It's guaranteed that these roads connected all nnn places.
    On the following line there're kkk different positive integers x1,x2…xkx_1,x_2 ldots x_kx1,x2xk separated by spaces. These are the numbers of places the persons are at.

    输出描述:

    A non-negative integer - the minimal time for persons to meet together.
    示例1

    输入

    复制
    4 2
    1 2
    3 1
    3 4
    2 4

    输出

    复制
    2

    说明

    They can meet at place 1 or 3.

    备注:

    1≤n≤1051 leq n leq 10^51n105
    题目大意:给你一颗树,树中某些结点上有人,问你这些人在全部在一点会面的最小是时间是多少
    思路:显然就是求最远的两个关键点之间的距离了
    看代码:
    #include<iostream>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int maxn=1e5+5;
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    typedef long long LL;
    const LL INF=1e18;
    int cnt=0;
    int head[maxn],dis[maxn];
    int a[maxn];
    bool vis[maxn],key[maxn];
    queue<int>q;
    struct E
    {
        int to,next;
    }edge[maxn<<1];
    void add(int u,int v)
    {
    //    cout<<"u:"<<u<<" v:"<<v<<endl;
        edge[cnt].to=v;
        edge[cnt].next=head[u];
        head[u]=cnt++;
    }
    void bfs(int x)
    {
    //    cout<<"2:"<<vis[2]<<endl;
        vis[x]=true;
        dis[x]=0;
        q.push(x);
        while(!q.empty())
        {
           int u=q.front();q.pop();
           for(int i=head[u];i!=-1;i=edge[i].next)
           {
                int v=edge[i].to;
                if(!vis[v])
                {
    
                    dis[v]=dis[u]+1;
    //                cout<<"v:"<<v<<" dis[v]:"<<dis[v]<<endl;
                    vis[v]=true;q.push(v);
                }
           }
        }
    }
    int main()
    {
        memset(head,-1,sizeof(head));
        int N,K;
        cin>>N>>K;
        for(int i=1;i<N;i++)
        {
            int u,v;cin>>u>>v;
            add(u,v);add(v,u);
        }
        for(int i=1;i<=K;i++)
        {
            cin>>a[i];key[a[i]]=true;//标记是否为关键点
        }
        bfs(a[1]);//任取一个关键点
    //    for(int i=1;i<=N;i++) cout<<dis[i]<<" ";cout<<endl;
        int ma=dis[a[1]],id=a[1];
        for(int i=1;i<=N;i++)//找最远的关键点
        {
            if(key[i]&&dis[i]>ma)
            {
                ma=dis[i];id=i;
            }
        }
    //    cout<<"id:"<<id<<endl;
        memset(dis,0,sizeof(dis));
        memset(vis,false,sizeof(vis));
        bfs(id);
    //    for(int i=1;i<=N;i++) cout<<dis[i]<<" ";cout<<endl;
        ma=-1;
        for(int i=1;i<=N;i++)
        {
            if(key[i]&&dis[i]>ma)
            {
                ma=dis[i];
            }
        }
        cout<<(ma+1)/2<<endl;
        return 0;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    学习 TList 类的实现[1]
    Dll 使用 PChar 参数的小例子
    学习使用资源文件[11]
    【转载】OGRE 内存管理
    【转载】Ogre的内存分配策略
    【转载】.NET面试题系列[0]
    【转载】深入探讨透视投影坐标变换
    【转载】四元数-Quaterion
    【转载】齐次坐标
    【转载】深入研究Windows内部原理绝对经典的资料
  • 原文地址:https://www.cnblogs.com/caijiaming/p/11257804.html
Copyright © 2011-2022 走看看