2020 BIT冬训-图&&DFS&&BFS L - Three Paths on a Tree CodeForces - 1294F(树的直径)

问题描述

给出一个含有n个点的树。
你从树上钦定三个不同的点a,b,c,如果一个边在其中两个点的简单路径上,它就是“好边”。你需要求出最多有多少个"好边",并且输出任一一种选定a,b,c的方案。

输入格式

第一行一个整数n
接下来n-1行每行两个数a,b表示一条边的两个端点。

输出格式

第一行一个数表示好边最多有多少个。
第二行是三个数表示一种钦定a,b,c使得好边个数最多的方案。

样例输入

8
1 2
2 3
3 4
4 5
4 6
3 7
3 8

样例输出

5
1 8 6

数据范围

3<=n<=2e5

Note

样例对应的图片如下 :

本题的思路是先两次DFS求出树的直径。(树的直径的求法和定义见该链接

再BFS求出离直径最远的那个点。(如果没有分支那么就是直径)

AC代码如下:

#include <algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define MAXN 200005
using namespace std;
int n,temp1,temp2,spos,epos,dis[MAXN],vis[MAXN],cnt,tcnt,tmax,tpos;
vector<int>g[MAXN];
vector<int>d;
queue<int>q;
int find(int s,int e){
    if(s==e&&tcnt==cnt){//如果找到了终点且是最长路径,则返回1
        return 1; 
    } 
    vis[s]=1;
    for(int i=0;i<g[s].size();i++){
        if(!vis[g[s][i]]){
            d.push_back(g[s][i]);
            tcnt++;
            if(find(g[s][i],e))
                return 1;
            tcnt--;
            d.erase(d.end()-1);
        }
    }
    return 0;
}
void dfs(int s,int &e){
    if(cnt<dis[s]){
        cnt=dis[s];
        e=s;
    }
    vis[s]=1;
    for(int i=0;i<g[s].size();i++){
        if(!vis[g[s][i]]){
            dis[g[s][i]]=dis[s]+1;
            dfs(g[s][i],e);
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=0;i<n-1;i++){
        scanf("%d%d",&temp1,&temp2);
        g[temp1].push_back(temp2);
        g[temp2].push_back(temp1);
    }
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    cnt=0;
    dfs(1,spos);//第一次dfs,找到离1最远的点并赋给spos 
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    cnt=0;
    dfs(spos,epos);//第二次dfs,找到离spos最远的点并赋给epos。两次dfs后的spos和epos就是最短路径 
    memset(vis,0,sizeof(vis));
    d.push_back(spos);
    find(spos,epos);//找出直径上的点,并存入d 
    tcnt=0;
    if(cnt==n-1){//如果所有点都在直径上,那么答案为直径长度,直径的起点终点和中间任意一点 
        printf("%d\n%d %d %d\n",cnt,spos,epos,d[1]);
    }else{//如果有分支,即有点不在直径上,则取一个距直径最远的点加入即可。 
        memset(vis,0,sizeof(vis));
        memset(dis,0,sizeof(dis));
        for(int i=0;i<d.size();i++){//bfs求各点到直径的距离 
            vis[d[i]]=1;
            q.push(d[i]);
        }
        tmax=0;
        while(!q.empty()){
            int u =q.front();
            q.pop();
            for(int i=0;i<g[u].size();i++){
                if(!vis[g[u][i]]){
                    dis[g[u][i]]=max(dis[g[u][i]],dis[u]+1);
                    if(tmax<dis[g[u][i]]){//更新最远距离和点的下标 
                        tmax=dis[g[u][i]];
                        tpos=g[u][i];
                    }
                    vis[g[u][i]]=1;
                    q.push(g[u][i]);
                }
            
            }
        }
        printf("%d\n%d %d %d\n",cnt+tmax,spos,epos,tpos);
    } 
}

 

posted @ 2021-03-05 20:18  mikku  阅读(64)  评论(0)    收藏  举报