带花树

一般图最大匹配问题

可以理解成高级版的匈牙利算法,在二分图匹配中,环都是偶环,所以可以将点分成两部分,不会冲突,但是一般图中会出现奇环,这是直接增广就变得不可行。

考虑在增广时遇到一个奇环是什么情况,环中至少有一个点,可以向外侧匹配,这时,我们把一个奇环缩成一个点,再跑匈牙利就行了,可以增广时,把环拆开,把每个点对应的匹配连上就行了

记录一个 \(lk\) 表示每个点匹配的是哪个点, 记录一个 \(pre\) 表示每个点被哪个点遍历到,在缩点的时候,把 \(pre\) 变成双向的,就行了

一般图最大匹配模板 \(code\)

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define rg register
inline int read(){
    rg char ch = gc();
    rg int x = 0, f = 0;
    while(!isdigit(ch)) f |= (ch == '-'), ch = gc();
    while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = gc();
    return f ? -x : x;
}
const int N = 1e3 + 5, M = 1e5 + 5;
int head[N], ver[M], nxt[M], tot;
inline void add(int x, int y){
    ver[++tot] = y;
    nxt[tot] = head[x];
    head[x] = tot;
}
inline void adds(int x, int y){ add(x, y); add(y, x); }
int n, m;
int lk[N], pre[N], dfn[N], f[N];
int q[N], ql, qr, cl[N], cnt;
int find(int x){
    return f[x] ? f[x] = find(f[x]) : x;
}
inline int lca(int x, int y){
    ++cnt;
    while(true){
        if(dfn[x = find(x)] == cnt) return x;
        if(x) dfn[x] = cnt; x = pre[lk[x]]; swap(x, y);
    }
}
inline void flw(int x, int y, int p){
    while(find(x) ^ p){
        pre[x] = y; y = lk[x];
        if(cl[y] == 2) cl[y] = 1, q[++qr] = y;
        f[x] = f[y] = p; x = pre[y];
    }
}
inline bool dfs(int x){
    memset(f, 0, sizeof f);
    memset(cl, 0, sizeof cl);
    memset(pre, 0, sizeof pre);
    cl[q[ql = qr = 1] = x] = 1;
    for(int x = q[ql]; ql <= qr; x = q[++ql]){
        for(int y, z, i = head[x]; i; i = nxt[i]){
            if(cl[y = ver[i]] == 2) continue;
            if(find(y) == find(x)) continue;
            if(cl[y] == 1) z = lca(x, y), flw(x, y, z), flw(y, x, z);
            else{
                cl[y] = 2; pre[y] = x;
                if(!lk[y]){
                    for(int u = y, v, lst; u; u = lst)
                        lst = lk[v = pre[u]], lk[u] = v, lk[v] = u;
                    return true;
                }
                cl[lk[y]] = 1; q[++qr] = lk[y];
            }
        }
    }
    return false;
}

signed main(){
    n = read(), m = read();
    rep(i, 1, m) adds(read(), read());
    int ans = 0;
    rep(i, 1, n) ans += (!lk[i] && dfs(i));
    printf("%d\n", ans);
    rep(i, 1, n) printf("%d ", lk[i]);
    gc(), gc();
    return 0;
}

例题

挑战 NPC

posted @ 2020-06-06 11:28  __int256  阅读(112)  评论(0编辑  收藏  举报