1 条题解

  • 0
    @ 2025-8-24 21:52:07

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Ch1F4N
    HN 初三最菜 OIer|| 新的赛季 rp ++

    搬运于2025-08-24 21:52:07,当前版本为作者最后更新于2023-08-07 20:42:53,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    简要题意是找到一条边连接使得最大团大小增加。

    在补图上最大团等于最大独立集。

    所以问题转化为删掉一条边使得最大独立集增加,又因为团不超过两个,所以原图是二分图,也就是使得最大匹配减少。

    考虑什么样的匹配边是可以被代替的,先跑一遍网络流求最大匹配,不难发现假若一条匹配在残量网络流上的一个环中,那么它就是可以被代替的,所以对残量网络进行缩点,两个端点不在同一个强连通分量中的匹配边可以作为答案。

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 1e4 + 114;
    const int maxm = 2e6 + 114;
    const int inf = 0x3f3f3f3f;
    int maxflow, vis[maxn], tot = 1, cnt;
    int s, t, n, m, Q, E;
    vector<int> edge[maxn], Road[maxn];
    int hd[maxn], road[maxn], dis[maxn];
    map<int, int> f[maxn];
    struct edge {
        int next, to, w;
    } e[maxm * 2];
    void add(int u, int v, int w) {
        e[++tot].to = v;
        f[u][v] = tot;
        e[tot].w = w;
        e[tot].next = hd[u];
        hd[u] = tot;
        e[++tot].to = u;
        e[tot].w = 0;
        e[tot].next = hd[v];
        hd[v] = tot;
    }
    bool bfs() {
        memset(dis, 0, sizeof(dis));
        dis[s] = 1;
        queue<int>Q;
        Q.push(s);
    
        while (!Q.empty()) {
            int u = Q.front();
            Q.pop();
            road[u] = hd[u];
    
            for (int i = hd[u]; i; i = e[i].next) {
                int v = e[i].to;
    
                if (!dis[v] && e[i].w) {
                    dis[v] = dis[u] + 1;
                    Q.push(v);
                }
    
            }
        }
    
        return dis[t] != 0;
    }
    int dinic(int now, int res) {
        if (now == t)
            return res;
    
        int tp = res;
    
        for (int i = road[now]; i; i = e[i].next) {
            int v = e[i].to;
            road[now] = i;
    
            if (dis[v] == dis[now] + 1 && e[i].w) {
                int k = min(e[i].w, tp);
                int del = dinic(v, k);
                e[i].w -= del;
                e[i ^ 1].w += del;
                tp -= del;
    
                if (!tp)
                    break;
            }
        }
    
        return res - tp;
    }
    int col[maxn], Use[maxn];
    void dfs(int u) {
        if (Use[u] == 1)
            return ;
    
        Use[u] = 1;
    
        for (int v : edge[u])
            col[v] = col[u] ^ 1, dfs(v);
    }
    int dfsn[maxn];
    int low[maxn];
    stack<int> S;
    int Vis[maxn], use[maxn];
    int color[maxn], sum = 0;
    int deep = 0;
    void paint(int u) {
        S.pop();
        color[u] = sum;
        Vis[u] = 0;
    }
    void tanjan(int u) {
        dfsn[u] = ++deep;
        low[u] = deep;
        Vis[u] = 1;
        use[u] = 1;
        S.push(u);
    
        for (int i = hd[u]; i; i = e[i].next) {
            if (e[i].w == 0)
                continue;
    
            int v = e[i].to;
    
            if (dfsn[v] == 0) {
                tanjan(v);
                low[u] = min(low[u], low[v]);
            } else {
                if (Vis[v] != 0) {
                    low[u] = min(low[u], low[v]);
                }
            }
        }
    
        if (dfsn[u] == low[u]) {
            sum++;
    
            while (S.top() != u) {
                paint(S.top());
            }
    
            paint(u);
        }
    
        return ;
    }
    set< pair<int, int>> chifan;
    int main() {
        cin >> n >> m;
    
        for (int i = 1; i <= m; i++) {
            int u, v;
            cin >> u >> v;
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
    
        for (int i = 1; i <= n; i++) {
            if (Use[i] == 0)
                col[i] = 0, dfs(i);
        }
    
        for (int i = 1; i <= n; i++) {
            if (col[i] == 0) {
                for (int nxt : edge[i])
                    Road[i].push_back(nxt), add(i, nxt, 1);
            }
        }
    
        s = n + 1, t = n + 2;
    
        for (int i = 1; i <= n; i++)
            if (col[i] == 0)
                add(s, i, 1);
            else
                add(i, t, 1);
    
        while (bfs() == true)
            maxflow += dinic(s, inf);
    
        for (int i = 1; i <= n + 2; i++) {
            if (use[i] == 0)
                tanjan(i);
        }
    
        for (int i = 1; i <= n; i++) {
            for (int nxt : Road[i]) {
                if (e[f[i][nxt]].w == 0 && color[i] != color[nxt]) {
                    chifan.insert(make_pair(min(i, nxt), max(i, nxt)));
                }
            }
        }
    
        cout << chifan.size() << '\n';
    
        for (pair<int, int> OUT : chifan) {
            cout << OUT.first << ' ' << OUT.second << '\n';
        }
    }
    
    • 1

    信息

    ID
    1300
    时间
    1000ms
    内存
    125MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者