关于此题 [ABC239F] Construct Highway 的一些总结

传送门

  • 题目大意:给定n个点和m条已有的边,并指定每个点的度数,问能否构建出满足条件的树

  • 思路:首先所有度数之和应该是2(n1) (因为每条边会被算两次)。对于输入的每条边,我们让其对应所需的度数减一,得到的就是我们所构建出的树中,每个点需要我们人为额外加上的度数。此时如果有某个点所需度数为负就直接输出-1。那么此时,我们可以得到每个连通块所需要的总度数,我们根据每个连通块的需要的总度数,将这些连通块分为两类:第一类,所需总度数为1;第二类,所需总度数大于等于2。此时我们要进行的操作是,枚举每个第二类连通块,将其需要度数的点与第一类连通块中需要度数的点连边。假设此第二类连通块所需总度数d,那么我们连上d1条边,最后剩一个点还需连接一条边时,此第二类连通块就变成了第一类连通块,于是将其加入第一类连通块当中。在此过程中如果发现第一类连通块不够了,就直接输出-1。最后再让第一类连通块之间相互匹配,即可。注意此处用连通块所需总度数来分类而不是各个点的度数来分类,是因为如果按照后者情况我们有可能连上与自己在同一连通块内的点形成环,而想要避免这种情况又会花费O(n2)的复杂度。

代码:

#include<bits/stdc++.h>
    
using namespace std;
    
int t;
const int N = 2e5 + 10;
int fat[N],n,m,in[N],tot;
int cnt[N];
vector<int> q1;
vector<vector<int> > q2;
vector<int> nde[N];
struct node {
    int x,y;
}ans[N];

int find(int x) {
    return (fat[x] == x ? fat[x] : fat[x] = find(fat[x]));
}

void unionn(int x,int y) {
    x = find(x);
    y = find(y);
    fat[x] = y;
}

bool check() {
    int fg = find(1);
    for(int i = 2;i <= n;i++) if(fg != find(i)) return true;
    return false;
}
    
void solve() {
    cin >> n >> m;
    for(int i = 1;i <= n;i++) cin >> in[i],fat[i] = i;
    if(accumulate(in + 1,in + 1 + n,0) != 2 * n - 2) return (void)puts("-1");
    for(int u,v,i = 1;i <= m;i++) {
        cin >> u >> v;  
        in[u]--;in[v]--;
        unionn(u,v);
        if(in[u] < 0 || in[v] < 0) return (void)puts("-1");
    }
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= in[i];j++)
            nde[find(i)].emplace_back(i);
    for(int i = 1;i <= n;i++) 
        if(nde[i].size() == 1) q1.emplace_back(nde[i][0]);
        else if(nde[i].size() > 1) q2.emplace_back(nde[i]);
    for(auto&& i : q2) {
        for(int j = 1;j < i.size();j++) {
            if(q1.empty()) return (void)puts("-1");
            ans[++tot] = {i[j],q1.back()};
            unionn(i[j],q1.back());
            q1.pop_back();
        }
        q1.push_back(i[0]);
    }
    if(q1.size() & 1) return (void)puts("-1");
    for(int i = 0;i < q1.size();i += 2) {
        ans[++tot] = {q1[i],q1[i + 1]};
        unionn(q1[i],q1[i + 1]);
    }
    if(check()) return (void)puts("-1");
    for(int i = 1;i <= tot;i++) cout << ans[i].x << ' ' << ans[i].y << '\n';
}
    
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    t = 1;
    while(t--) solve();
    
    return 0;
}
posted @   孤枕  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示
相见争如不见,多情何似无情。