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 }