zoukankan      html  css  js  c++  java
  • [CF9E] Interesting Graph and Apples

    [CF9E] Interesting Graph and Apples - 构造,并查集

    Description

    给出 n 个点,m 条边,问是否能通过加一些边,使得 n 个点构成有且仅有 n 条边的单个环。如果能,输出 YES 以及加上的边的条数,并按字典序打印加上的边的两个端点。如果有多组解,输出字典序最小的一种方法。否则输出 NO 即可。

    Solution

    做法其实比较丰富,尽量去弄一个简单点不容易错的

    先特判两种特殊情况:不需要加任何边(连通,所有点度数都是 2),没救(有点的度数大于 2,有自环)

    剩下的情况一定可以构造出解

    我们先枚举一个点 i,再枚举一个点 j,如果这两个点所在集合不连通,并且度数都小于 2,就连边

    这样做一遍下来以后,一定可以串成一条链

    显然不会出现度数大于 2 的点
    对于每个 i,如果它和任何另一个 j 所在集合不连通,那么枚举到那个集合的链端时一定会连上一条边

    最后,我们找到两个度数为 1 的点,连边,就完事了

    (代码已经混乱不堪了)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        int n, m;
        cin >> n >> m;
    
        if (n == 1 && m == 0)
        {
            cout << "YES
    1
    1 1" << endl;
            return 0;
        }
    
        vector<int> fa(n + 2);
        for (int i = 1; i <= n; i++)
            fa[i] = i;
    
        vector<int> d(n + 2);
    
        function<int(int)> find = [&](int x) -> int {
            return x == fa[x] ? x : fa[x] = find(fa[x]);
        };
    
        function<void(int, int)> merge = [&](int x, int y) -> void {
            x = find(x);
            y = find(y);
            fa[x] = y;
        };
    
        int circle_flag = 0, self_circle = 0;
    
        for (int i = 1; i <= m; i++)
        {
            int u, v;
            cin >> u >> v;
            if (u == v)
                self_circle = 1;
            if (find(u) == find(v))
                circle_flag = 1;
            merge(u, v);
            d[u]++;
            d[v]++;
        }
    
        int min_deg = 1e9, max_deg = 0;
        for (int i = 1; i <= n; i++)
        {
            min_deg = min(min_deg, d[i]);
            max_deg = max(max_deg, d[i]);
        }
        if (max_deg > 2 || (self_circle && n > 1))
        {
            cout << "NO" << endl;
        }
        else if ((circle_flag && min_deg == 2 && max_deg == 2))
        {
            cout << "YES" << endl
                 << 0 << endl;
        }
        else
        {
            vector<pair<int, int>> ans;
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= n; j++)
                    if (j != i)
                    {
                        if (find(i) != find(j) && d[i] < 2 && d[j] < 2)
                        {
                            ans.push_back({min(i, j), max(i, j)});
                            d[i]++;
                            d[j]++;
                            merge(i, j);
                        }
                    }
            }
            vector<int> tmp;
            for (int i = 1; i <= n; i++)
                if (d[i] < 2)
                    tmp.push_back(i);
            ans.push_back({tmp[0], tmp[1]});
            int flag = 1;
            if (tmp.size() == 2)
            {
                d[tmp[0]]++;
                d[tmp[1]]++;
                for (int i = 1; i <= n; i++)
                    if (d[i] != 2)
                        flag = 0;
            }
            else
            {
                flag = 0;
            }
            if (flag)
            {
                cout << "YES" << endl
                     << n - m << endl;
                for (auto [x, y] : ans)
                    cout << x << " " << y << endl;
            }
            else
            {
                cout << "NO" << endl;
            }
        }
    }
    
  • 相关阅读:
    数组是个好东西
    排列(permutation) 用1,2,3,…,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要 求abc:def:ghi=1:2:3。按照“abc def ghi”的格式输出所有解,每行一个解。
    子序列的和
    韩信点兵
    水仙花数
    阶乘之和
    3n+1问题
    MongoDB 安装
    mysql中bigint在php中表示
    Android之NDK开发
  • 原文地址:https://www.cnblogs.com/mollnn/p/14406777.html
Copyright © 2011-2022 走看看