F. Three Paths on a Tree
原题链接:https://codeforces.com/contest/1294/problem/F
题目大意:
给定一棵树,选出三点,使三点连成的j简单路径最大。简而言之,三个点连成的边的集合大小。
解题思路:
假设任取一点为三点连线的公共点,最长路径就是这个点到其他三个点的三条最长边之和,可知这个点一定在直径上(画图分析假设不在时的最长路径可反证)。所以先求出树的直径,在使用$ans =(a b+a c+b c) / 2$遍历可以得到第三个点。
代码:
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int maxn=2e5+10;
4 vector<int> a[maxn];
5 int n,vis[maxn],dis1[maxn],dis2[maxn],dis[maxn],pos;
6 void bfs(int x){
7 memset(vis,0,sizeof(vis));
8 memset(dis,0,sizeof(dis));
9 pos=x;
10 vis[x]=1,dis[x]=0;
11 queue<int> q;
12 q.push(x);
13 while(!q.empty()){
14 int u=q.front();q.pop();
15 for(int i=0;i<a[u].size();i++){
16 if(!vis[a[u][i]]){
17 vis[a[u][i]]=1;
18 dis[a[u][i]]=dis[u]+1;
19 q.push(a[u][i]);
20 if(dis[a[u][i]]>dis[pos]) pos=a[u][i];
21 }
22 }
23 }
24 }
25 int main(){
26 scanf("%d",&n);
27 int u,v;
28 for(int i=1;i<n;i++){
29 scanf("%d%d",&u,&v);
30 a[u].push_back(v);
31 a[v].push_back(u);
32 }
33 int a,b,c;
34 bfs(1);
35 a=pos;
36 bfs(pos);
37 b=pos;
38 for(int i=1;i<=n;i++){
39 dis1[i]=dis[i];
40 }
41 bfs(pos);
42 for(int i=1;i<=n;i++){
43 dis2[i]=dis[i];
44 }
45 c=0;
46 for(int i=1;i<=n;i++){
47 if(dis1[i]+dis2[i]>dis1[c]+dis2[c]&&i!=a&&i!=b){
48 c=i;
49 }
50 }
51 int ans=(dis1[b]+dis1[c]+dis2[c])/2;
52 cout<<ans<<endl<<a<<" "<<b<<" "<<c;
53 return 0;
54 }