两种树的直径求法

两种树的直径求法

两遍DFS

优点:方便记录直径的两端点。

缺点:无法除理带负权的树。

void dfs1(int now,int len)
{
    if(len>maxl)
    {
        maxl=len;
        s=now;///找端点
    }
    for(int i=head[now];i;i=nxt[i])
        if(to[i]!=f[now])dfs1(to[i],len+1);
}
void dfs2(int now,int len,int fa)
{
    if(len>maxl)
    {
        maxl=len;
        t=now;///找端点
    }
    for(int i=head[now];i;i=nxt[i])
        if(to[i]!=fa)dfs2(to[i],len+1,now);
}

树形DP

优点:短,可以处理有负权的树。

缺点:不好记录端点,容易打错。

void dfs3(int now)
{
    for(int i=head[now];i;i=nxt[i])
    {
        if(to[i]!=f[now])
        {
            dfs3(to[i]);
            lzj2=max(lzj2,dis[now]+dis[to[i]]+q[i]);
            dis[now]=max(dis[now],dis[to[i]]+q[i]);
        }
    }
}

 一道充分体现出两种方法特点的好练习题

最初每条路要走两遍,修一条路就可使与它形成环的路少走一遍,先找到直径,然后把与直径形成环的点边的边权改为-1(因为每条路至少走一遍,第一次少走1,第二次就不能少走了),然后再找一次直径。

#include<bits/stdc++.h>
using namespace std;
const int MM=1000006,inf=0x3f3f3f3f;
int dis[MM],nxt[MM*2],to[MM*2],head[MM],q[MM*2],dep[MM],f[MM],tot,maxl,s,t,n,k,u,v,zj[MM],lzj1,lzj2;
void add(int u,int v)
{
    nxt[++tot]=head[u];
    head[u]=tot;
    to[tot]=v;
    q[tot]=1;
}
void dfs(int now,int deep,int fa)
{
    dep[now]=deep;
    f[now]=fa;
    for(int i=head[now];i;i=nxt[i])
        if(to[i]!=f[now])dfs(to[i],deep+1,now);
}
void dfs1(int now,int len)
{
    if(len>maxl)
    {
        maxl=len;
        s=now;
    }
    for(int i=head[now];i;i=nxt[i])
        if(to[i]!=f[now])dfs1(to[i],len+1);
}
void dfs2(int now,int len,int fa)
{
    if(len>maxl)
    {
        maxl=len;
        t=now;
    }
    for(int i=head[now];i;i=nxt[i])
        if(to[i]!=fa)dfs2(to[i],len+1,now);
}
void dfs3(int now)
{
    for(int i=head[now];i;i=nxt[i])
    {
        if(to[i]!=f[now])
        {
            dfs3(to[i]);
            lzj2=max(lzj2,dis[now]+dis[to[i]]+q[i]);
            dis[now]=max(dis[now],dis[to[i]]+q[i]);
        }
    }
}
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n-1;i++)
    {
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    dfs(1,1,0);
    dfs1(1,0);
    dfs2(s,0,0);
    if(dep[s]<dep[t])
        swap(s,t);
    while(dep[s]>dep[t])
        zj[s]=1,s=f[s];
    lzj1=maxl;
    if(k==1)
    {
        cout<<(n-1)*2-lzj1+1;
        return 0;
    }
    while(s!=t)
    {
        zj[s]=1,zj[t]=1;
        s=f[s],t=f[t];
    }
    zj[s]=1;
    for(int i=1;i<=n;i++)
    {
        if(zj[i])
        {
            for(int j=head[i];j;j=nxt[j])
            {
                if(zj[to[j]])
                    q[j]=-1;
            }
        }
    }
    dfs3(1);
    //cout<<lzj1<<' '<<lzj2<<endl;
    cout<<(n-1)*2-(lzj1+lzj2)+2;
    return 0;
} 

 

posted @ 2021-09-27 13:54  T_X蒻  阅读(43)  评论(0编辑  收藏  举报