CF 1092E - Minimal Diameter Forest 构造算法,贪心,树,搜索

You are given a forest — an undirected graph with nn 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 nn and mm (1≤n≤10001≤n≤1000, 0≤m≤n−10≤m≤n−1) — the number of vertices of the graph and the number of edges, respectively.

Each of the next mm lines contains two integers vv and uu (1≤v,u≤n1≤v,u≤n, v≠uv≠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(n−1)−m lines should contain two integers vv and uu (1≤v,u≤n1≤v,u≤n, v≠uv≠u) — the descriptions of the added edges.

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

For m=n−1m=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

input

Copy

4 2
1 2
2 3

output

Copy

2
4 2

input

Copy

2 0

output

Copy

1
1 2

input

Copy

3 2
1 3
2 3

output

Copy

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.

 

 

大意:

给你一个森林  其中每棵树有自己的直径  要你把森林的每棵树都连成一棵新树 让新生成的树直径最小
一棵树是一个无向无环图
一个森林则是若干个不连通的树组成的图
树的直径的定义是一棵树中任意两顶点间的最短路中最长的一条

 

思路:

对于森林里的每一棵树,找到一个顶点,使得该点与树上任意一点的最大距离最小,该点为中心。(一棵树可能有2个中心,取任意一个),找到直径最大的一棵树,将该树的中心与其他树的中心连接起来。 令树t1,t2的中心为u,v,diam1为t1的直径,diam2为t2直径,d1为u到t1上任意一点的最大距离,d2为v到t2上任意一点的最大距离,那么连接两棵树后可得到的最小直径是 d=max(diam1,diam2,d1+d2+1), 使d1,d2最小则可得到最小的d

#include<bits/stdc++.h>
using namespace std;
const int maxn=200*1000+13;
const int INF=0x3f3f3f3f;

int n,m;
vector<int>g [maxn];

int bfs(int x,int dist[maxn]){
    queue<int> q;
    q.push(x);
    dist[x]=0;
    int lst=-1;
    while(!q.empty()){
        int v=q.front();
        q.pop();
        lst=v;
        for (auto u : g[v]) if (dist[u] > dist[v] + 1){
            dist[u]=dist[v]+1;
            q.push(u);
        }
    }
    return lst;
}

int distFromX[maxn],distFromY[maxn];
bool used[maxn];
vector<int> cur;

void dfs(int x){
    used[x]=true;
    cur.push_back(x);
    for(auto u:g[x]) if(!used[u]) dfs(u);
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        int v,u;
        scanf("%d%d",&v,&u);
        v--;u--;
        g[v].push_back(u);
        g[u].push_back(v);
    }
    for(int i=0;i<n;i++) distFromX[i]=distFromY[i]=INF;
    vector<pair<int,int>>comps;
    for(int i=0;i<n;i++) if(!used[i]){
            cur.clear();
            dfs(i);
            int x=bfs(i,distFromY);  //find the position of x
            int y=bfs(x,distFromX);
            for(auto u:cur) distFromY[u]=INF;
            bfs(y,distFromY);        //update distFromY array
            int d=distFromX[y],center;
            for(auto u:cur) if(distFromX[u]==d/2&&distFromY[u]==d-d/2)
                center=u;
            comps.push_back({d,center});
        }
    vector<pair<int,int>>ans;
    nth_element(comps.begin(),comps.end()-1,comps.end());
    int sz=comps.size()-1;
    for(int i=0;i<sz;i++){
        g[comps[i].second].push_back(comps.back().second);
        g[comps.back().second].push_back(comps[i].second);
        ans.push_back({comps[i].second,comps.back().second});
    }
    for(int i=0;i<n;i++) distFromX[i]=distFromY[i]=INF;
    int y=bfs(bfs(comps.back().second,distFromY),distFromX);
    printf("%d\n",distFromX[y]);
    for(auto u:ans) printf("%d %d\n",u.first+1,u.second+1);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值