zoukankan      html  css  js  c++  java
  • 带花树

    一般图最大匹配问题

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

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

    记录一个 (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
    ", ans);
        rep(i, 1, n) printf("%d ", lk[i]);
        gc(), gc();
        return 0;
    }
    

    例题

    挑战 NPC

  • 相关阅读:
    PLL详解
    CSI-2 协议
    C语言volatile关键字的用法
    联合体(union)的使用方法及其本质
    Linux驱动之LED驱动编写
    insmod 和第一个驱动
    黑电平校正BLC
    什么是HDR?
    使用starUML画顺序图
    UML 资料整理
  • 原文地址:https://www.cnblogs.com/XiaoVsun/p/13054024.html
Copyright © 2011-2022 走看看