构造+割点,F2. Spanning Tree with One Fixed Degree

一、题目

1、题目描述

2、输入输出

2.1输入

2.2输出

3、原题链接

Problem - 1133F2 - Codeforces


二、解题报告

1、思路分析

考虑以根节点为割点,会有若干个连通块

连通块的数目为根节点至少要连出去的边,不妨记为mi

如果mi > D,那么无解

如果根节点的度 < D,那么无解

否则先把一定要连出去的边连了,然后再连D - mi条边

然后处理结果即可

2、复杂度

时间复杂度: O(N+M)空间复杂度:O(N+M)

3、代码详解

#include <bits/stdc++.h>
using PII = std::pair<int, int>;
using i64 = long long;
 
const int inf = 1e9;
 
 
void solve() {
    int N, M, D;
    std::cin >> N >> M >> D;
    std::vector<std::vector<int>> g(N);
    std::vector<int> p(N, -1);
    auto find = [&](auto&& self, int x) -> int {
        return p[x] < 0 ? x : p[x] = self(self, p[x]);
    };
 
    auto merge = [&](int x, int y) -> void {
        int px = find(find, x), py = find(find, y);
        if (px == py) return;
        if (p[px] > p[py]) std::swap(px, py);
        p[px] += p[py], p[py] = px;
    };
 
    for (int i = 0, u, v; i < M; i ++ ) {
        std::cin >> u >> v, -- v, -- u;
        g[u].push_back(v), g[v].push_back(u);
    }
 
    std::vector<bool> vis(N);
    vis[0] = true;
    auto dfs1 = [&](auto&& self, int u, int fa) -> void{
        
        vis[u] = true;
        for (int v : g[u]) {
            if (v == fa || vis[v])  continue;
            merge(u, v);
            self(self, v, u);
        }
    };
 
    std::unordered_set<int> st;
    for (int v : g[0])
        if (!vis[v])
            dfs1(dfs1, v, 0), st.insert(find(find, v));
 
    if (st.size() > D || g[0].size() < D) {
        std::cout << "NO";
        return;
    }
 
    std::vector<std::array<int, 2>> ans; ans.reserve(N - 1);
    vis.assign(N, false), vis[0] = true;
    
    auto dfs2 = [&](auto&& self, int u, int fa) -> void {
        vis[u] = true;
        for (int v : g[u])
            if (!vis[v] && v != fa)
                ans.push_back( { u + 1, v + 1 } ), self(self, v, fa);
    };
 
    for (int v : g[0]) 
        if (st.count(find(find, v))) 
            vis[v] = true, ans.push_back( { 1, v + 1 } ), D --, st.erase(find(find, v));
 
    for (int v : g[0])
        if (!vis[v] && D)
            vis[v] = true, ans.push_back( { 1, v + 1 } ), D --;
 
 
    for (int v : g[0]) 
        if (vis[v]) 
            dfs2(dfs2, v, 0);
 
    if (ans.size() + 1 == N) {
        std::cout << "YES\n";
        for (auto& [x, y] : ans)
            std::cout << x << ' ' << y << '\n';
    }
    else 
        std::cout << "NO\n";
}
 
 
int main () {
    std::ios::sync_with_stdio(false);   std::cin.tie(0);  std::cout.tie(0);
    int _ = 1;
    // std::cin >> _;
    while (_ --)
        solve();
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值