Codeforces Contest 1092 problem E Minimal Diameter Forest —— 找树上最中间点的方法

82 篇文章 1 订阅

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 m lines 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 descriptions of the added edges.

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

For m=n−1 no 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
inputCopy
4 2
1 2
2 3
outputCopy
2
4 2
inputCopy
2 0
outputCopy
1
1 2
inputCopy
3 2
1 3
2 3
outputCopy
2
Note
In the first example adding edges (1, 4) or (3, 4) will lead to a total diameter of 3. Adding edge (2, 4), however, will make it 2.

Edge (1, 2) is the only option you have for the second example. The diameter is 1.

You can’t add any edges in the third example. The diameter is already 2.

题意:

给你一个森林,让你将所有树都连起来构成一棵树,然后使得树上的最远距离最小。

题解:

一看到就知道是找到所有树的种间点,然后将其他树的中间点连到最大的这棵树的中间点上,之后又有两种情况:最大的树的一半与第二大的一半+1或者第二大与第三大+2,也是一眼就能看出来的,问题在于中间点怎么找,我原本设想所有叶子结点往中间找,找到一个点,看了别人写的知道有另外一种方法,先找到深度最深的点,在从那个点找到离他最远的点,这样就是树的直径了,在找的过程中我们记录每个点的父亲,最后在从最深的点回溯到一半的地方。

#include<bits/stdc++.h>
using namespace std;
#define pa pair<int,int>
const int N=1e3+5;
int dep[N],vis[N],fa[N];
vector<pa>vec,ans;
struct node
{
    int to,next;
}e[N*2];
int cnt,head[N];
void add(int x,int y)
{
    e[cnt].to=y;
    e[cnt].next=head[x];
    head[x]=cnt++;
}
vector<int>all;
void dfs(int x,int f)
{
    dep[x]=dep[f]+1;
    vis[x]=1;
    fa[x]=f;
    all.push_back(x);
    for(int i=head[x];~i;i=e[i].next)
    {
        int ne=e[i].to;
        if(ne==f)
            continue;
        dfs(ne,x);
    }
}
bool cmp(pa a,pa b)
{
    return a.second>b.second;
}
int main()
{
    memset(head,-1,sizeof(head));
    int n,m;
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
    int last=0,maxn=0;
    for(int j=1;j<=n;j++)
    {
        if(!vis[j])
        {
            dfs(j,0);
            last=0;
            for(int i=0;i<all.size();i++)
                last=dep[all[i]]>dep[last]?all[i]:last;
            all.clear();
            dfs(last,0);
            last=0;
            for(int i=0;i<all.size();i++)
                last=dep[all[i]]>dep[last]?all[i]:last;
            all.clear();
            int deep=(dep[last]+1)/2;
            int m=dep[last];
            maxn=max(maxn,dep[last]-1);
            while(deep!=dep[last])
                last=fa[last];
            vec.push_back({last,max(dep[last]-1,m-dep[last])});
        }
    }
    sort(vec.begin(),vec.end(),cmp);
    for(int i=1;i<vec.size();i++)
    {
        ans.push_back({vec[i].first,vec[0].first});
        maxn=max(maxn,vec[i].second+vec[0].second+1);
    }
    if(vec.size()>2)
        maxn=max(maxn,vec[2].second+vec[1].second+2);
    printf("%d\n",maxn);
    for(int i=0;i<ans.size();i++)
        printf("%d %d\n",ans[i].first,ans[i].second);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值