直径+贪心——cf1294F

/*
在树上找三个点,似的这三个形成的路径覆盖边数最多
结论:一定是直径+直径上最深的叶子 
把直径拉出来,然后直径上每个结点dfs一次就可以 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 400005

vector<int>G[N];
int n,s,t,d[N],vis[N],id,Max;

void getdeep(int u,int pre){
    for(auto v:G[u]){
        if(v==pre)continue;
        d[v]=d[u]+1;
        getdeep(v,u);
    }
}

vector<int>path;
int getpath(int u,int pre){
    int flag=0;
    if(u==t){path.push_back(u);return 1;}
    for(auto v:G[u]){
        if(v==pre)continue;
        if(getpath(v,u))
            flag=1;
    }
    
    if(flag)path.push_back(u);
    return flag;
}

void dfs(int u,int pre){
    for(auto v:G[u]){
        if(vis[v] || v==pre)continue;
        d[v]=d[u]+1;
        dfs(v,u);
    }
}

int main(){
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }    
    s=1;
    getdeep(s,s);
    for(int i=1;i<=n;i++)
        if(d[i]>d[s])s=i;
    
    memset(d,0,sizeof d);
    getdeep(s,s);
    for(int i=1;i<=n;i++)
        if(d[i]>d[t])t=i;
    int ans=d[t];
        
    getpath(s,s);
//    for(auto x:path)cout<<x<<" ";
    memset(d,0,sizeof d);
    for(auto x:path)vis[x]=1;
    for(auto x:path)dfs(x,x);
    Max=-1;
    for(int i=1;i<=n;i++)if(!vis[i]){
        if(Max<d[i])Max=d[i],id=i;
    }
    if(Max==-1){
        for(int i=1;i<=n;i++) 
            if(i!=s && i!=t)id=i;
        Max=0;
    }
    ans+=Max;
    
    cout<<ans<<'\n';
    cout<<s<<" "<<t<<" "<<id<<'\n';
} 

 

posted on 2020-02-04 14:53  zsben  阅读(152)  评论(0编辑  收藏  举报

导航