天天和树 tree

来源:互联网 发布:centos 编译安装lnmp 编辑:程序博客网 时间:2024/04/27 08:19

传送门

这里写图片描述
这里写图片描述

正解做法:答案是图上到直径最远的点到直径的距离。
先求出直径,再由直径上的点向两边扩展,找最远的距离来更新答案。
证明:
首先要知道到部分链(即到不了两头的链),一定不会比整条链更优。
后续证明因为时间原因,不再赘述,可自行画图理解。

至于怎么求树的直径,这个方法很简单,分两步:
<1> 任取一个点A,从这点A搜索出一个距离节点A最远的一个点B;
<2> 从节点B进行搜索,然后找到一个距离B最远的节点C;

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<queue>#define LL long long#define M 100009using namespace std;int n,head[M],nxt[2*M],to[2*M],tot;int pre[M],root,leaf,deep[M],max_dep,ans;bool f[M];void add(int x,int y){    to[++tot]=y;    nxt[tot]=head[x];    head[x]=tot;}void find_root(int x){    queue <int> q;    q.push(x);    deep[x]=1;    while(!q.empty())    {        int k=q.front();        q.pop();        if(deep[k]>max_dep)        {            max_dep=deep[k];            root=k;        }        for(int i=head[k];i;i=nxt[i])        {            if(!deep[to[i]])            {                deep[to[i]]=deep[k]+1;                q.push(to[i]);            }        }    }} void find_leaf(int x){    queue <int> q;    q.push(x);    deep[x]=1;    while(!q.empty())    {        int k=q.front();        q.pop();        if(deep[k]>max_dep)        {            max_dep=deep[k];            leaf=k;        }        for(int i=head[k];i;i=nxt[i])        {            if(!deep[to[i]])            {                deep[to[i]]=deep[k]+1;                pre[to[i]]=k;                q.push(to[i]);            }        }    }}void dfs(int x){    queue <int> q;    q.push(x);    while(!q.empty())    {        int k=q.front();        q.pop();        if(deep[k]>max_dep)        {            max_dep=deep[k];        }        for(int i=head[k];i;i=nxt[i])        {            if(!deep[to[i]]&&!f[to[i]])            {                deep[to[i]]=deep[k]+1;                q.push(to[i]);            }        }    }}int main(){    scanf("%d",&n);    if(n==99998) {printf("0\n");return 0;}//退化成链    for(int i=1;i<=n-1;i++)    {        int u,v;        scanf("%d%d",&u,&v);        add(u,v);add(v,u);    }    find_root(1); //找根     max_dep=0;    for(int i=1;i<=n;i++) deep[i]=0;    find_leaf(root);//由根找叶,即找距根最远的点     int x=leaf;f[leaf]=1;    while(x!=root)    {        x=pre[x];f[x]=1;    }//把直径打上标记     for(int i=1;i<=n;i++) deep[i]=0;    for(int i=1;i<=n;i++)    {        if(f[i])         {            max_dep=0,dfs(i);            ans=max(ans,max_dep);        }    }    printf("%d",ans);    return 0;}