# Codeforces Round #527 (Div. 3)-E. Minimal Diameter Forest-树的直径与合并

6 篇文章 0 订阅

## codeforce-1092-E. Minimal Diameter Forest-树的直径与合并

### 【Description】

You are given a forest — an undirected graph with n vertices such that each its
connected component is a tree.

The diameter (aka "longest shortest path") of a connected undirected graph is the
maximum number of edges in the shortest path between any pair of its vertices.

You task is to add some edges (possibly zero) to the graph so that it becomes a tree
and the diameter of the tree is minimal possible.

If there are multiple correct answers, print any of them.


### 【Input】

The first line contains two integers n and m (1≤n≤1000, 0≤m≤n−1) — the number of
vertices of the graph and the number of edges, respectively.

Each of the next mlines contains two integers v and u (1≤v,u≤n, v≠u) — the descriptions
of the edges.

It is guaranteed that the given graph is a forest.


### 【Output】

In the first line print the diameter of the resulting tree.

Each of the next (n−1)−m lines should contain two integers v and u (1≤v,u≤n, v≠u) — the

The resulting graph should be a tree and its diameter should be minimal possible.

For m=n−1no edges are added, thus the output consists of a single integer — diameter of
the given tree.

If there are multiple correct answers, print any of them.


### 【Examples】

##### Sample Input
4 2
1 2
2 3

##### Sample Output
2
4 2

##### Sample Input
2 0

##### Sample Output
1
1 2

##### Sample Input
3 2
1 3
2 3

##### Sample Output
2


### 【Problem Description】

首先定义一棵树的直径为 树上任意两点的最短距离中最长的那个值。



### 【Solution】

在所有树中，找到直径最大的一个，然后将其他所有树的直径中点挂在直径最大的那棵树的直径中点即可。

1、求直径：

v是u的一个直接子节点。

2、对于每个直径找中点。

3、合并

1、当两棵树直径都为1的时候，总直径要加2， 比如1-2，3-4

2、当两棵树的直径差小于等于1的时候，总直径要加1

3、当两棵树直径都是奇数时，并且直径差为2时，总直径要加1



### 【Code】

/*
* @Author: Simon
* @Date: 2019-01-17 15:30:26
*/
#include<bits/stdc++.h>
using namespace std;
typedef int Int;
#define int long long
#define INF 0x3f3f3f3f
#define maxn 1005
int a[maxn];
bool vis[maxn]; //标记是否访问过
vector<int>g[maxn];
struct node{
int Max,Mvet;
}dia[maxn];//第i课树的直接，以及直径上的一个点
bool cmp(node a,node b){
return a.Max>b.Max;
}
int gras[maxn];//节点i在最长路径上的儿子
int dianum=0;//总共dianum棵树
int vMax[maxn];//以i为根节点的子树的深度减一
int dfs(int u){
vis[u]=1;
for(auto v:g[u]){
if(!vis[v]){
dfs(v);
if(vMax[u]+vMax[v]+1>dia[dianum].Max){//所有树的最大直径
dia[dianum].Max=vMax[u]+vMax[v]+1;
dia[dianum].Mvet=u;
}
if(vMax[v]+1>vMax[u]){//求vMax数组
vMax[u]=vMax[v]+1;
gras[u]=v;
}
}
}
}
Int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++){
int u,v;scanf("%lld%lld",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++){
if(!vis[i]) dianum++,dia[dianum].Max=0,dia[dianum].Mvet=i,dfs(i);//遍历每棵树
}
sort(dia+1,dia+dianum+1,cmp);
int Maxv=1,Maxdia=dia[1].Max;
for(int i=1;i<=dianum;i++){
int val=vMax[dia[i].Mvet];
for(int j=val;j>(dia[i].Max+1)/2;j--){//找到每棵树直径的中点
dia[i].Mvet=gras[dia[i].Mvet];
}
if(Maxv==i) continue;
if(Maxdia==1&&dia[i].Max==1) Maxdia+=2;//三个特判
else if (abs(dia[i].Max - Maxdia) <= 1) Maxdia +=1;
else if(abs(dia[i].Max-Maxdia)==2&&(dia[i].Max&1)&&(Maxdia&1)) Maxdia++;
}
printf("%lld\n",Maxdia);
for(int i=2;i<=dianum;i++){
printf("%lld %lld\n",dia[Maxv].Mvet,dia[i].Mvet);
}
cin.get(),cin.get();
return 0;
}

• 1
点赞
• 1
收藏
觉得还不错? 一键收藏
• 0
评论
08-21 1607
07-01 694
10-21 197
08-22 3809
02-16 189

### “相关推荐”对你有帮助么？

• 非常没帮助
• 没帮助
• 一般
• 有帮助
• 非常有帮助

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