树的直径--Cf GYM 100781A

题目大意:
给出若干棵树,用最少的边把它们连成一张无向连通图,同时使图的直径最小

solution:
求每个树的直径,直径的中心相连,菊花形,把其他树的直径中点连到半径最大的树的直径中点上
根据连接情况讨论计算图的直径

答案有三种:第一种是添加了边之后,树的最长路径还是原来子树的路径,第二种是对子树长度进行排序后,两个最长的距离分别除以2向上取整后加上1。第三种比较难注意到,就是第二第三长的分别除以2向上取整后加上2,因为可能隔着一条边之后比第一种情况更长了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define maxn 100005
using namespace std;
int n,m,cnt,head[maxn],num,d[maxn],t,dis[maxn],b[maxn],ans;
bool vis[maxn];

inline int rd(){
  int x=0,f=1; char c=' ';
  while(c<'0' || c>'9') {if(c=='-') f=-1;c=getchar();}
  while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
  return x*f;
}

struct EDGE{
  int to,nxt;
}edge[maxn*2];

void add(int x,int y){
  edge[++cnt].to=y;
  edge[cnt].nxt=head[x];
  head[x]=cnt;
}

void dfs(int x){
  vis[x]=1; b[x]=num;
  for(int i=head[x];i;i=edge[i].nxt){
    int v=edge[i].to;
    if(vis[v]) continue;
    dis[v]=dis[x]+1;
    if(d[num]<dis[v]) d[num]=dis[v],t=v;
    dfs(v);
  }
  return;
}

int main(){
  n=rd(); m=rd();
  for(int i=1;i<=m;i++){
    int x=rd(),y=rd();
    add(x,y); add(y,x);
  }
  for(int i=1;i<=n;i++){
    if(!b[i]) {
      t=-1; num++;
      if(!head[i]) continue;//不加这玩意居然t了???
      dfs(i);
      memset(dis,0,sizeof dis); memset(vis,0,sizeof vis);
      if(t>=0) dfs(t);//这里t要判断一下,如果是单点的话t就是上一个联通块的t了qwq
    }
  }
  sort(d+1,d+num+1);
  ans=d[num];
  if(num>1) ans=max(ans,(d[num]+1)/2+(d[num-1]+1)/2+1);
  if(num>2) ans=max(ans,(d[num-1]+1)/2+(d[num-2]+1)/2+2);
  printf("%d\n",ans);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值