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";
}
 
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号