树的直径

前言

那年,CCF把CSP-S办成了植树节...

为了准备以后的植树节,教练也在机房让大家种树..


最近一直在接触树上知识,先来讲讲树的直径绝对不是因为只搞懂了这个

树的直径,即在一棵树中,最远的两个节点之间的距离,也可以指这条路径。下面树的直径都指的是它的距离长度。

Tree dp或是两次搜索的时间复杂度都是\(O(n)\)不会树形dp所以不写


思路

大致思路是这样的,从根节点(任意一个点都可以)P出发,一次搜索找到离这个点距离最远的点Q,再从点Q出发再次搜索,搜到离Q最远的点W,这样两次搜索到的两个节点Q,W就是直径的两个端点。这样的方法代码量略大,但是可以比较方便地(指与Tree dp比较)记录路径。


证明

怎么证明这种方法找到的就是树的直径呢?

这里需要分类讨论。

1.P在直径上。

根据树的直径的定义,Q一定也在直径上。而且因为离直径上的点最远,它还是直径的一个端点。

2.P不在直径上。

我们用反证法,假设此时PQ不是直径,AB是直径。

1

树的直径_第1张图片

第一种情况,如图,若AB与PQ有交点C,由于P到Q最远,那么PC+CQ>PC+CA,所以CQ>CA,易得CQ+CB>CA+CB,即CQ+CB>AB,与AB是直径矛盾,所以假设不成立。(其中AB,PQ不一定是直线,画成直线是为了方便)

2

树的直径_第2张图片

第二种情况,如图,若AB与PQ没有交点,M为AB上任意一点,N为PQ上任意一点。首先还是NP+NQ>NQ+MN+MB,同时减掉NQ,得NP>MN+MB,易知NP+MN>MB,所以NP+MN+MA>MB+MA,即NP+MN+MA>AB,与AB是直径矛盾,所以这种情况也不成立。

证毕。


代码

\(BFS版\)

#include
using namespace std;
struct node
{
    int to,w,next;
} e[100010*2];
int head[100010],f[100010],n,m,tot;
bool vis[100010];
void add_edge(int from,int to,int cost){e[++tot].next=head[from],head[from]=tot,e[tot].to=to,e[tot].w=cost;}
void bfs(int v)
{
    queue  q;
    while(!q.empty()) q.pop();
    memset(f,0,sizeof(f));
    memset(vis,0,sizeof(vis));
    q.push(v);
    vis[v]=1;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=e[i].next)
            if(f[e[i].to]==0&&!vis[e[i].to])
            {
                f[e[i].to]=f[x]+e[i].w;
                q.push(e[i].to);
            }
    }
}
 
int main()
{
    int u,v,w;
    scanf("%d%d",&n,&m);
    tot=0;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
        add_edge(v,u,w);
    }
    bfs(1);
    int maxn=0;
    for(int i=1;i<=n;i++)
        if(f[i]>f[maxn])maxn=i;
    bfs(maxn);
    int ans=0;
    for(int i=1;i<=n;i++)
        if(f[i]>ans)ans=f[i];
    printf("%d\n",ans);
    return 0;
}

\(DFS\)

#include

using namespace std;

long long dst[200010],t,dep[200010],son[200010],maxx,head[200010],ff[200010],vis[200010];
long long s,l,r,ans,n,m,num;

struct node
{
    int to,nex;
    long long v;
}e[400010];

void add(int from,int to,long long v)
{
    e[++num].to=to;
    e[num].v=v;
    e[num].nex=head[from];
    head[from]=num;
}

void dfs(int x,int fa)
{
    for(int i=head[x];i;i=e[i].nex)
    {
        int v=e[i].to;if(v==fa)continue;
        ff[v]=x;
        dst[v]=dst[x]+e[i].v;
        dfs(v,x);
    }
}


int main()
{
    cin>>n;
    for(int i=1;i>u>>v>>w;
        add(u,v,w);
        add(v,u,w);
    }
    
    dfs(1,0);
    
    for(int i=1;i<=n;i++)
        if(dst[i]>maxx)maxx=dst[i],s=i,dst[i]=0;
        
    dfs(s,0);
    
    maxx=0;
    
    for(int i=1;i<=n;i++)
        if(dst[i]>maxx)maxx=dst[i],t=i;
        
    printf("%lld\n",maxx);
    
    return 0;
}

你可能感兴趣的:(树的直径)