树的直径| CF#615Div3 F. Three Paths on a Tree

F. Three Paths on a Tree

思路

两种方法:

1.两次bfs求树的直径,顺便求出一个直径端点到所有点的最短距离;再bfs一次,求另一个直径上的端点到其它所有点的最短距离;之后枚举第三个端点(不等于端点1和端点2),dis(a,b) + dis(b,c) + dis(a,c) 再除以 2 就是最终答案,因为每个路径走了两次所以除以2。

2.dfs求树的直径,记录直径上的所有点。从直径上的所有点去搜索它们到不在直径上的点的最远距离。最后直径+这个最远距离就是答案

代码1

bfs

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2e5+10;
struct edge{
    int v;
    edge(int v){
        this -> v = v;
    }
};
vector<edge> vec[maxn];
int d[maxn],ans,dis1[maxn],dis2[maxn];
bool vis[maxn];
int node; // 记录第一次dfs最远的点
void bfs(int u){
    queue<int> q;
    q.push(u);
    while(!q.empty()){
        int x = q.front();
        vis[x] = 1;
        q.pop();
        for(int i = 0;i < (int)vec[x].size();i++){
            int y = vec[x][i].v;
            if(vis[y]) continue;
            d[y] = d[x] + 1;
            if(d[y] > ans){
                ans = d[y];
                node = y;
            }
            q.push(y);
        }
    }
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n-1;i++){
		int u,v;
		scanf("%d%d",&u,&v);
        vec[u].push_back(edge(v));
        vec[v].push_back(edge(u));
	}
    memset(vis,0,sizeof(vis));
    ans = 0;
    d[1] = 0;
    bfs(1);
    int s1 = node;
    memset(vis,0,sizeof(vis));
    ans = 0;
    d[node] = 0;
    bfs(node);
    memset(vis,0,sizeof(vis));
    int s2 = node;
	int ans1 = ans;
   	for(int i=1;i<=n;i++)    dis1[i]=d[i];
   	bfs(node);
    for(int i=1;i<=n;i++)    dis2[i]=d[i];
    int s3 = 0;
	for(int i=1;i<=n;i++){
		if(dis1[i]+dis2[i]>dis1[s3]+dis2[s3] && i!=s1 && i!=s2) 
			s3=i;
	}
	int ans=(dis1[s1]+dis1[s3]+dis2[s3])/2;
	cout<<ans<<endl;
	cout<<s1<<" "<<s2<<" "<<s3;
    return 0;
}

代码2

dfs

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e5+5;
int vis[maxn],book[maxn];
vector<int> g[maxn]; 
int node = 1;
int path[maxn];
int n,m;
int ans = 0;

void init(){
	for(int i=1;i<=n;i++) {
		path[i] = -1;
		vis[i] = 0;
	}
}

//dfs求树的直径 
void dfs(int x,int dis){
    vis[x] = 1; 
    for(int i=0;i<g[x].size();i++){
        int vv = g[x][i];
        if(!vis[vv]){
            path[vv] = x;
            if(dis + 1 > ans) {
            	node = vv;
            	ans = dis+1;
			}
            dfs(vv,dis+1);
        }
    }
    vis[x] = 0;
}


int lastDis = 0;
int lastId = 0;

void dfs2(int x,int num){
	if(lastDis < num){
		lastDis = num;
		lastId = x;
	}
	for(int i=0;i<g[x].size();i++){
		int v = g[x][i];
		if(!book[v]){
			book[v] = 1;
			dfs2(v,num+1);
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;
		cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	init();
	dfs(1,0);
	int t1 = ans;
	ans = 0;
	int s1 = node;
	init();
	dfs(node,0);
	int s2 = node;
	int id = 1;
	//树的直径上的点 都作标记 
	for(int i=s2;i!=-1;i=path[i]){
		book[i] = 1;
		if(i != s1 && i != s2) 
			id = i; //树呈直线型 选一个点作为第三点 
	}
	int maxDist = ans;
	for(int i=1;i<=n;i++){
		//从标记过的点去搜索 到未标记过的点的距离 
		if(book[i] == 1){
			lastDis = 0;
			dfs2(i,0);
			if(ans < maxDist + lastDis){
				ans = maxDist + lastDis;
				id = lastId;
			}
		}
	}
	cout<<ans<<endl;
	cout<<s1<<" "<<s2<<" "<<id<<endl;
	return 0;
} 
/*
8 7
1 2
2 3
3 4
4 5
4 6
3 7
3 8

4 3
1 2
2 3
3 4
*/
原文地址:https://www.cnblogs.com/fisherss/p/12294003.html