cf 1133 F2 https://codeforces.com/contest/1133/problem/F2

F2. Spanning Tree with One Fixed Degree

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given an undirected unweighted connected graph consisting of nn vertices and mm edges. It is guaranteed that there are no self-loops or multiple edges in the given graph.

Your task is to find any spanning tree of this graph such that the degree of the first vertex (vertex with label 11 on it) is equal to DD (or say that there are no such spanning trees). Recall that the degree of a vertex is the number of edges incident to it.

Input

The first line contains three integers nn, mm and DD (2≤n≤2⋅1052≤n≤2⋅105, n−1≤m≤min(2⋅105,n(n−1)2),1≤D<nn−1≤m≤min(2⋅105,n(n−1)2),1≤D<n) — the number of vertices, the number of edges and required degree of the first vertex, respectively.

The following mm lines denote edges: edge ii is represented by a pair of integers vivi, uiui (1≤vi,ui≤n1≤vi,ui≤n, ui≠viui≠vi), which are the indices of vertices connected by the edge. There are no loops or multiple edges in the given graph, i. e. for each pair (vi,uivi,ui) there are no other pairs (vi,uivi,ui) or (ui,viui,vi) in the list of edges, and for each pair (vi,ui)(vi,ui) the condition vi≠uivi≠ui is satisfied.

Output

If there is no spanning tree satisfying the condition from the problem statement, print "NO" in the first line.

Otherwise print "YES" in the first line and then print n−1n−1 lines describing the edges of a spanning tree such that the degree of the first vertex (vertex with label 11 on it) is equal to DD. Make sure that the edges of the printed spanning tree form some subset of the input edges (order doesn't matter and edge (v,u)(v,u) is considered the same as the edge (u,v)(u,v)).

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

Examples

input

Copy

4 5 1
1 2
1 3
1 4
2 3
3 4

output

Copy

YES
2 1
2 3
3 4

input

Copy

4 5 3
1 2
1 3
1 4
2 3
3 4

output

Copy

YES
1 2
1 3
4 1

input

Copy

4 4 3
1 2
1 4
2 3
3 4

output

Copy

NO

Note

The picture corresponding to the first and second examples:

The picture corresponding to the third example:

 

n个点,m条边,没有边权,求一个生成树第一个点度数为d(即输出的编号为1的点度数为d),并且输出这颗生成树

 

大概做法就是,考虑先拆边,把1附近的边拆掉,然后遍历一下看看剩下的还有多少联通快,如果个数num == d,直接跑边,输出就可以,如果num < d,比如下图这种情况(图很丑)考虑连边使得不连通的变连通,联通的话则不连边,所以并查集乱写一下就可以了(因为以前详细画了图,结果一关没保存到,实在懒得画了,过了好多天才发出来 。。。。)想了一天还是继续写完吧,观察下图,我们考虑拆边

 

用两个并查集先来维护连通快,然后去遍历拆掉的1的边,如果我们对于上图d == 4,连接1的边,保证让不联通的连通,所以需要用两个并查集在联通的时候判断一下,连到发现可以联通的时候,但是这个时候d = 3,所以还少一个边,随便加一个边,那我们再去在第二个并查集里,去连那些连通块,连到可以联通的时候就可以了,并且把这些边记录下来即可

#include <bits/stdc++.h>
#include <time.h>


using namespace std;

typedef long long ll;
typedef double db;
int xx[4] = {1,-1,0,0};
int yy[4] = {0,0,1,-1};
const double eps = 1e-9;
typedef pair<int,int>  P;
const int maxn = 2e6 + 5000;
const ll mod = 1e9 + 7;
inline int sign(db a) {
    return a < -eps ? -1 : a > eps;
}
inline int cmp(db a,db b) {
    return sign(a - b);
}
ll mul(ll a,ll b,ll c) {
    ll res = 1;
    while(b) {
        if(b & 1) res *= a,res %= c;
        a *= a,a %= c,b >>= 1;
    }
    return res;
}
ll phi(ll x) {
    ll res = x;
    for(ll i = 2; i * i <= x; i++) {
        if(x % i == 0) res = res / i * (i - 1);
        while(x % i == 0) x /= i;
    }
    if(x > 1) res = res / x  * (x - 1);
    return res;
}
int fa[maxn];
int fa1[maxn];
int Find(int x) {
    if(x != fa[x]) return fa[x] = Find(fa[x]);
    return fa[x];
}
int Find1(int x) {
    if(x != fa1[x]) return fa1[x] = Find1(fa1[x]);
    return fa1[x];
}
ll c,n,k;
vector<vector<int> >v;
int m;
int vis[maxn];
P p[maxn];
vector<P>E[maxn];
vector<P>ans;
vector<P>vvv;

int main() {
    int d;
    ios::sync_with_stdio(false);
    while(cin >> n >> m >> d) {
        v.resize(n + 500);
        memset(vis,0,sizeof(vis));
        for(int i = 1; i <= n; i++) fa[i] = i,fa1[i] = i;
        for(int i = 1; i <= m; i++) {
            int u,vv;
            cin >> p[i].first >> p[i].second;
            vis[p[i].first]++;
            vis[p[i].second]++;
            if(p[i].first == 1 || p[i].second == 1) {
                vvv.push_back(p[i]);
            }
        }
        if(vis[1] < d){
            cout << "No" << endl;
            continue;
        }
        for(int i = 1; i <= m; i++) {
            if(p[i].first != 1 &&  p[i].second != 1) {
                int X = Find(p[i].first);
                int Y = Find(p[i].second);
                if(X != Y)
                    fa[X] = Y;
            }
        }
        for(int i = 1; i <= n; i++) fa[i] = Find(i);

        int cnt = 1;
        for(int i = 2; i <= n; i++)     if(i == fa[i]) vis[i] = cnt++;
//        cout << vis[i] << " *** "<< i << endl;
        for(int i = 0; i < vvv.size(); i++) {
//            cout << vvv[i].first << " " << vvv[i].second << "  " << endl;
            if(vis[fa[vvv[i].first]] || vis[fa[vvv[i].second]]) {
                int X = Find(vvv[i].first);
                int Y = Find(vvv[i].second);
                int X1 = Find1(vvv[i].first);
                int Y1 = Find1(vvv[i].second);
                if(X != Y) fa[X] = Y,fa1[X1] = Y1, ans.push_back(vvv[i]);
            }
            if(ans.size() == cnt - 1) break;
        }
//        cout << ans.size() << endl;
        cnt--;
//        cout << cnt << " d = " << d << endl;
        if(cnt < d) {
//                printf("das\n");
            for(int i = 0; i < vvv.size(); i++) {
                int X = Find(vvv[i].first);
                int Y = Find(vvv[i].second);
                int X1 = Find1(vvv[i].first);
                int Y1 = Find1(vvv[i].second);
//                cout << X << "  ---- " << Y << endl;
//                cout << X1  << " --- " << Y1 << endl;
//                if(X == Y) {
//                    if(X1 != Y1) {
//                        fa1[X1] = Y1;
//                    }
//                } else {
                if(X1 != Y1) {
                    fa1[X1] = Y1;
//                        fa[X] = Y;
//                    cout << vvv[i].first << "  ++++ " << vvv[i].second << endl;
                    ans.push_back(vvv[i]);
                    cnt++;
//                    }
                }
                if(cnt == d) break;
            }
        }
//        cout << ans.size() << endl;
        for(int i = 1; i <= n; i++) fa1[i] = Find1(fa1[i]);
        for(int i = 1; i<= m; i++) {
            if(p[i].first != 1 && p[i].second != 1) {
                int X1 = Find1(p[i].first);
                int Y1 = Find1(p[i].second);
                if(X1 != Y1) {
//                    cout << X1 << " ..... " << Y1 << endl;
                    fa1[X1] = Y1;
                    ans.push_back(p[i]);
                }
            }
            if(ans.size() == n - 1) break;
        }
        int num = 0;
        for(auto d:ans) {
             if(d.first == 1 || d.second == 1) num++;
        }
        if(num > d || num < d){
            cout << "No" << endl;
            continue;
        }
        cout<< "Yes" << endl;
        for(auto d:ans) {
            cout << d.first << " " << d.second << endl;
        }

        cerr << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值