树的直径| 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
*/