[HAOI2017] new urbanization, bipartite graph and the maximum matching a necessary edge feasible point

The meaning of problems

To fill a given FIGS FIG ensure artwork may be divided into no more than two groups. For each edge in the complement graph, is determined after addition of this edge in the original graph, the maximum group size is increased.

Data range: \ (n-\ 100000 Leq, m \ Leq 150000 \)

answer

Easy to find, complement is a bipartite graph in FIG.

Thus, the maximum group in the artwork corresponding to the maximum independent set up on the FIG.

Bipartite graph maximum independent set \ (= \) Points \ (- \) Maximum number of matches

Simply determine whether each side must be in the biggest matches.

First run again bipartite graph matching the maximum flow, then run again on the point tarjan condensing residual network. If one side is matched, and the two end points are not in the same strongly connected component, it is necessary that the edge side.

Two end points is not a strongly connected components, that is not an endpoint from one end to another augmenting path, that this edge is irreplaceable.

Some expansion

The maximum possible bipartite graph matching edge

It refers to the presence of a maximum matching comprising this edge.

Either this edge has been determined in the matching, this edge or two endpoints in the same strongly connected components.

Bipartite graph maximum matching a necessary point

Just go through obtain non-point can be.

From \ (S \) start, go \ (cap = 1 \) side, go all \ (X \) points are part of the answer; from \ (T \) start, go \ (cap = 0 \) side, go all \ (Y \) points are part of the answer.

Sensibility to understand: First, a point not match will be go, go through these points are non-point. A maximum point if the matching point must pass through a non-point, it will be able to be matched in a not replaced. Not from a match in \ (X \) the starting point Ministry to take the non-matching edge \ (Y \) section, if the match can go back to the edge, then the flip side of all matching and non-matching edge, you can not use matching It points out that instead of matching the \ (X \) unit point.

Maximum feasible point bipartite graph matching

That a possible side by side is necessary or feasible point.

#pragma GCC optimize("2,Ofast,inline")
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define LL long long
#define pii pair<int, int>
using namespace std;
const int N = 1e6 + 10;

template <typename T> T read(T &x) {
    int f = 0;
    register char c = getchar();
    while (c > '9' || c < '0') f |= (c == '-'), c = getchar();
    for (x = 0; c >= '0' && c <= '9'; c = getchar())
        x = (x << 3) + (x << 1) + (c ^ 48);
    if (f) x = -x;
    return x;
}

int n, m, E, S, T, tim, sccn;
int u[N], v[N];
int fir[N], nex[N], arr[N], vis[N], cap[N], col[N];
int dis[N], cur[N];
int top, st[N], dfn[N], low[N], scc[N];
vector<pii> ans;

inline void Add_Edge(int x, int y, int c) {
    nex[++E] = fir[x];
    fir[x] = E; arr[E] = y; cap[E] = c;
    nex[++E] = fir[y];
    fir[y] = E; arr[E] = x; cap[E] = 0;
}

void dfs(int x) {
    vis[x] = 1;
    for (int i = fir[x]; i; i = nex[i]) {
        if (vis[arr[i]]) continue;
        col[arr[i]] = col[x] ^ 1;
        dfs(arr[i]);
    }
}

int bfs() {
    queue<int> Q;
    memset(dis, 0x3f, sizeof dis);
    dis[S] = 0; Q.push(S);
    while (!Q.empty()) {
        int x = Q.front(); Q.pop();
        for (int i = fir[x]; i; i = nex[i]) {
            if (cap[i] && dis[arr[i]] > dis[x] + 1) {
                dis[arr[i]] = dis[x] + 1;
                Q.push(arr[i]);
            }
        }
    }
    return (dis[T] < 1e9);
}

int dinic(int x, int mf) {
    if (!mf || x == T) return mf;
    int ans = 0;
    for (int &i = cur[x]; i; i = nex[i]) {
        if (!cap[i] || dis[arr[i]] != dis[x] + 1) continue;
        int del = dinic(arr[i], min(cap[i], mf));
        cap[i] -= del; cap[i ^ 1] += del;
        ans += del; mf -= del;
        if (!mf) break;
    }
    return ans;
}

void tarjan(int x) {
    dfn[x] = low[x] = ++tim;
    st[++top] = x;
    for (int i = fir[x]; i; i = nex[i]) {
        if (!cap[i]) continue;
        if (!dfn[arr[i]]) {
            tarjan(arr[i]);
            low[x] = min(low[x], low[arr[i]]);
        }
        else if (!scc[arr[i]]) {
            low[x] = min(low[x], dfn[arr[i]]);
        }
    }
    if (low[x] == dfn[x]) {
        int y;
        ++sccn;
        do {
            y = st[top--];
            scc[y] = sccn;
        } while (x != y);
    }
}

int main() {
    read(n); read(m);
    for (int i = 1; i <= m; ++i) {
        int x, y;
        read(x); read(y);
        Add_Edge(x, y, 0);
        u[i] = x; v[i] = y;
    }
    for (int i = 1; i <= n; ++i) {
        if (!vis[i]) {
            dfs(i);
        }
    }
    memset(fir, 0, sizeof fir);
    E = 1;
    for (int i = 1; i <= m; ++i) {
        if (col[u[i]]) swap(u[i], v[i]);
        Add_Edge(u[i], v[i], 1);
    }
    S = n + 1; T = n + 2;
    for (int i = 1; i <= n; ++i) {
        if (!col[i]) Add_Edge(S, i, 1);
        else Add_Edge(i, T, 1);
    }
    while (bfs()) {
        for (int i = 1; i <= n + 2; ++i) {
            cur[i] = fir[i];
        }
        dinic(S, n);
    }
    for (int i = 1; i <= n + 2; ++i) {
        if (!scc[i]) tarjan(i);
    }
    for (int i = 1; i <= n; ++i) {
        if (col[i]) continue;
        for (int j = fir[i]; j; j = nex[j]) {
            if (cap[j]) continue;
            if (scc[i] != scc[arr[j]] && arr[j] != S && arr[j] != T) {
                ans.pb(mp(i, arr[j]));
            }
        }
    }
    for (int i = 0; i < ans.size(); ++i) {
        if (ans[i].fi > ans[i].se) {
            swap(ans[i].fi, ans[i].se);
        }
    }
    sort(ans.begin(), ans.end());
    cout << ans.size() << endl;
    for (int i = 0; i < ans.size(); ++i) {
        printf("%d %d\n", ans[i].fi, ans[i].se);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/Vexoben/p/11761040.html