AtCoder Beginner Contest 239 F Construct Highway

原题链接 ← Click it

题目大意:简言之就是给你一个森林,问你能不能用\(n - m - 1\)条边生成一个每个点度数为\(d_i\)的树。

解题思路:首先判断每个点的度数之和是否为\(2 * n - 2\),如果不等于,那么直接输出\(-1\)就可以了。其次考虑如何连边,对于每一个连通块而言(用并查集维护连通块),如果这个连通块中所有的点的剩余度数和为0,那么这个连通块就不能和其他的连通块相连了,因此,每一个连通块都至少拿出一个剩余度数来和其他的连通块连通。那么我们可以将剩余度数为1的连通块放一边,剩余度数大于1的连通块放另一边。我们每次都让剩余度数为1的连通块都和剩余度数大于1的连通块连通,如果剩余度数为1的连通块不够用了,那么输出\(-1\),因为假设剩余连通块的个数为\(k\),那么所有剩余连通块的度数和一定大于\(2 * k - 2\)。那么最后的情况是剩下剩余度数为1的两个连通块,那么将这两个连通块连通就得到了这颗生成树了。

参考代码:

typedef long long ll;
typedef pair<int, int> PII;
struct DSU {
    int N;
    vector<int> pr, size;
    DSU (int n) : N(n) {
        pr.resize(n + 1);
        size.resize(n + 1);
        for(int i = 1; i <= N; i ++) {
            pr[i] = i;
            size[i] = 1;
        }
    }
    int root(int x) {
        return pr[x] == x ? x : pr[x] = root(pr[x]);
    }
    bool same(int x, int y) {
        return root(x) == root(y);
    }
    bool unite(int x, int y) {
        int A = root(x), B = root(y);
        if(A == B) return 1;
        if(size[A] < size[B]) {
            pr[A] = B;
            size[B] += size[A];
        } else {
            pr[B] = A;
            size[A] += size[B];
        }
        return 0;
    }
};
void solve() {
    int n, m;
    cin >> n >> m;
    DSU dsu(n);
    vector<int> d(n + 1);
    for(int i = 1; i <= n; i ++) {
        cin >> d[i];
    }
    while(m -- ) {
        int a, b;
        cin >> a >> b;
        d[a] --, d[b] --;
        if(d[a] < 0 || d[b] < 0 || dsu.unite(a, b)) {
            cout << - 1 << '\n';
            return ;
        }  
    }
    vector<vector<int>> temp(n + 1);
    for(int i = 1; i <= n; i ++) {
        for(int _ = 0; _ < d[i]; _ ++) {
            temp[dsu.root(i)].push_back(i);
        }
    }
    vector<PII> res;
    vector<int> c1;
    vector<vector<int>> c2;
    for(int i = 1; i <= n; i ++) {
        if(temp[i].size() == 1) {
            c1.push_back(temp[i].back());
        } else if(temp[i].size() > 1){
            c2.push_back(temp[i]);
        }
    }
    for(auto it : c2) {
        for(int i = 0; i < it.size() - 1; i ++) {
            if(c1.empty()) {
                cout << -1 << '\n';
                return;
            }
            dsu.unite(c1.back(), it[i]);
            res.push_back({c1.back(), it[i]});
            c1.pop_back();
        }
        c1.push_back(it.back());
    }
    if(c1.size() == 2) {
        if(dsu.unite(c1[0], c1[1])) {
            cout << - 1 << '\n';
            return ;
        }
        res.push_back({c1[0], c1[1]});
    } else {
        cout << - 1 << '\n';
        return ;
    }
    if(dsu.size[dsu.root(1)] != n) {
        cout << - 1 << '\n';
        return ;
    }
    for(auto it : res) {
        cout << it.first << ' ' << it.second << '\n';
    }
}
posted @ 2022-03-07 20:04  Muly  阅读(71)  评论(2)    收藏  举报