P3731 题解

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

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

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

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

#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';
    }
}
posted @ 2024-01-31 00:00  ChiFAN鸭  阅读(5)  评论(0编辑  收藏  举报