AtCoder Beginner Contest 239 F - Construct Highway 「贪心」「构造」「并查集」

F - Construct Highway

题目描述:

构造一颗树,包含输入的所有边,且每个顶点都具有指定度数d[i]

思路:

首先根据树的定义以及度的定义等可以发现如果 ∑ 1 n d [ i ] ! = 2 ∗ ( n − 1 ) \sum_{1}^{n}d[i] !=2 * (n - 1) 1nd[i]!=2(n1),则一定不可以构造成功

如果满足这个条件了以后,我们考虑贪心,由于有已经存在的边,所有n个点变成了若干个联通块,而且存在的边的两个端点的度数应该减1,显然,每个联通块所需要的度是所有点的度数和。

贪心:对于度数为1的联通块,肯定是连度数大于等于2的联通块才最好,所以我们可以根据度数是否为1进行分组,分成度数为1的组和度数大于等于2的组。对于一个度数大于等于2的联通块,假设他的度数为d,我们只需要拿d-1个度数为1的点去匹配就行,然后剩下的那一个度数,就放到度数为1的那组里面,用于别的度数大于等于2的组的匹配,这样是最优的

最终匹配完了以后必须是有两个度数为1的点,否则则不行。此外还要利用并查集来判断n个点是否连接成了一个树

#include 
using namespace std;

#define endl '\n'
#define inf 0x3f3f3f3f
#define mod 1000000007
#define m_p(a,b) make_pair(a, b)
#define mem(a,b) memset((a),(b),sizeof(a))
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)

typedef long long ll;
typedef pair <int,int> pii;

#define MAX 300000 + 50
int n, m;
int x, y;
int d[MAX];
int fa[MAX];
inline int getfa(int x){
    return x == fa[x] ? x : fa[x] = getfa(fa[x]);
}
inline void emerge(int x, int y){
    fa[getfa(x)] = getfa(y);
}

void work(){
    cin >> n >> m;
    for(int i = 1; i <= n; ++i)cin >> d[i];
    for(int i = 1; i <= n; ++i)fa[i] = i;
    for(int i = 1; i <= m; ++i){
        cin >> x >> y;
        --d[x];
        --d[y];
        emerge(x, y);
    }
    vector<vector<int>>v(n + 1);
    for(int i = 1; i <= n; ++i){
        if(d[i] < 0){
            cout << -1 << endl;
            return;
        }
        int ff = getfa(i);
        for(int j = 1; j <= d[i]; ++j){
            v[ff].push_back(i);
        }
    }
    vector<int>ran;
    vector<vector<int>>ranran;
    for(int i = 1; i <= n; ++i){
        if(v[i].size() == 1)ran.push_back(v[i][0]);
        else if(v[i].size() > 1)ranran.push_back(v[i]);
    }
    vector<pii>ans;
    for(auto u : ranran){
        for(int i = 0; i < u.size() - 1; ++i){
            if(ran.empty()){
                cout << -1 << endl;
                return;
            }
            emerge(u[i], ran.back());
            ans.push_back(m_p(ran.back(), u[i]));
            ran.pop_back();
        }
        ran.push_back(u.back());
    }
    if(ran.size() != 2){
        cout << -1 << endl;
        return;
    }
    emerge(ran[0], ran[1]);
    ans.push_back(m_p(ran[0], ran[1]));
    for(int i = 1; i <= n; ++i){
        if(getfa(i) != getfa(1)){
            cout << -1 << endl;
            return;
        }
    }
    for(auto [u, v] : ans){
        cout << u << ' ' << v << endl;
    }
}


int main(){
    io;
    work();
    return 0;
}



你可能感兴趣的:(Atcoder,贪心算法,图论,构造,并查集)