CF1761E Make It Connected 记录

题目链接:https://codeforces.com/contest/1761/problem/E

题意简述

以邻接矩阵的形式给你一张无向图。你可以执行如下操作:

  • 选定节点 \(u\)。对所有其它节点 \(v\),翻转 \(u\)\(v\) 的连边状态。

给出一种花费操作最少的方案,使图连通。\(n \le 4000\)

题解

分类讨论+构造。VP 时这题我很快想出了具体思路,但因为一些小错误 WA 了好几发。

若图本来就是联通的,则无需操作。否则,若存在孤立点,对孤立点进行一次操作即可。

若存在不是完全图的连通块,最多只需一次操作。这里有两种独立的操作方案都可行:

  • 任选一个不是割点,且度数不是 \(n -1\)\(n\) 为连通片大小)的点 \(u\)。这样,连通片除去点 \(u\) 仍然是连通的;而且操作后,\(u\) 会与这一部分连通。操作后,\(u\) 也会与其它所有连通片连通,因此整个图连通。这样的点一定存在,证明略复杂,请移步官解

  • 或者更简单的方式是直接选择该连通片度数最小的点 \(v\)。反证法:若操作后,存在连通片 \(G_1\)\(u\) 不连通,则说明操作前 \(u\) 一定与 \(G_1\) 中每个点连边。若 \(G_1\) 不是完全图,这与 \(u\) 是度数最小的点矛盾。该连通片中除 \(G_1 + \set{u}\) 外一定有更多点,否则与连通片不是完全图矛盾。则 \(u\) 的度数大于 \(G_1\) 中点数,与 \(u\) 是度数最小的点矛盾。

则现在所有连通片都是完全图。

若只有两个连通片,则答案就是较小的连通片的大小。证明:观察可知,对 \(K_{a}, K_{b}\) 进行操作 \(a\)\(b\),分别变为 \(K_{a-1}, K_{b+1}\)\(K_{a+1}, K_{b-1}\) 。则对较小的连通片中的每个点依次操作即可。

否则,即有至少三个连通片。任选两个不在同一连通片中的点,先后操作即可,容易证明正确性。

除去读入及建图,时间复杂度 \(O(n + m)\)

实现(C++)

void solve() {
    int n;
    cin >> n;
    vector<vector<int>> adj(n);
    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        for (int j = 0; j < n; j++) {
            if (s[j] == '1') adj[i].push_back(j);
        }
    }
    vector<vector<int>> comp;
    vector<bool> vis(n, false);
    bool all_K = true;
    int not_K_id = -1;
    for (int i = 0; i < n; i++) {
        if (!vis[i]) {
            i64 ec = 0;
            comp.push_back({});
            queue<int> q;
            q.push(i);
            vis[i] = true;
            while (q.size()) {
                int u = q.front();
                q.pop();
                ec += adj[u].size();
                comp.back().push_back(u);
                for (int v : adj[u]) {
                    if (!vis[v]) {
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
            int vc = comp.back().size();
            if (ec != (i64)vc * (vc - 1)) {
                not_K_id = -1;
                all_K = false;
                for (int u : comp.back()) {
                    if ((int)adj[u].size() != vc - 1) {
                        if (not_K_id != -1) {
                            if (adj[not_K_id].size() > adj[u].size()) {
                                not_K_id = u;
                            }
                        } else {
                            not_K_id = u;
                        }
                    }
                }
            }
        }
    }
    ranges::sort(comp, [&](const auto &a, const auto &b) {
        return a.size() < b.size();
    });
    if (comp.size() == 1) {
        cout << 0 << "\n";
        return;
    }
    if (!all_K) {
        cout << 1 << "\n";
        cout << not_K_id + 1 << "\n";
        return;
    }
    if (comp[0].size() == 1) {
        cout << 1 << "\n";
        cout << comp[0][0] + 1 << "\n";
        return;
    }
    if (comp.size() == 2) {
        cout << comp[0].size() << "\n";
        for (int x : comp[0])
            cout << x + 1 << " ";
        cout << "\n";
        return;
    }
    cout << 2 << "\n";
    cout << comp[0][0] + 1 << " " << comp[1][0] + 1 << "\n";
}

posted @ 2023-12-23 00:33  cccpchenpi  阅读(56)  评论(0)    收藏  举报