CF GYM 100781A(菊花图+直径)

题目大意

给出若干颗树用最少的边把它们连成一个无向连通图,同时使图的直径最小。输出最小直径。

题解

我们定义树的半径为(树的直径+1)/2。符合题意的连接方式为。所有树的“中点”连在直径最长的树的中点上。

此时在判断最长直径即可。注意:有三种情况可以使直径最长。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cmath>
 6 using namespace std;
 7 const int N=200000;
 8 int vis[N],head[N],cnt,dp[N],ans[N],n,m,num;
 9 struct edge{
10     int to,nxt;
11 }e[N*4];
12 void add(int u,int v){
13     cnt++;
14     e[cnt].nxt=head[u];
15     head[u]=cnt;
16     e[cnt].to=v;
17 }
18 int getdp(int u){
19     vis[u]=1;
20     int ans=0;
21     for(int i=head[u];i;i=e[i].nxt){
22         int v=e[i].to;
23         if(vis[v])continue;
24         ans=max(ans,getdp(v));
25         ans=max(ans,dp[v]+dp[u]+1);
26         dp[u]=max(dp[u],dp[v]+1);
27     }
28     return ans;
29 }
30 int main(){
31     scanf("%d%d",&n,&m);
32     for(int i=1,a,b;i<=m;i++){
33         scanf("%d%d",&a,&b);
34         add(a,b);add(b,a);
35     }
36     for(int i=1;i<=n;i++){
37         if(vis[i]==0)ans[++num]=getdp(i);
38     }
39     sort(ans+1,ans+1+num);
40     printf("%d",max(ans[num],max((ans[num-1]+1)/2+(ans[num]+1)/2+1,(ans[num-1]+1)/2+(ans[num-2]+1)/2+2)));
41     return 0;
42 }
View Code
原文地址:https://www.cnblogs.com/Xu-daxia/p/9380906.html