zoukankan      html  css  js  c++  java
  • 二分图,匈牙利算法

    dfs写法

    const int maxn = 100024;
    
    struct nobe {
        int to;
        int lst;
    }edge[maxn];
    int head[128];
    int qsz = 1;
    
    inline void add(int u, int v) {
        edge[qsz].lst = head[u];
        edge[qsz].to  = v;
        head[u] = qsz++;    
    }
    
    int match[128];
    bool check[128];
    
    bool dfs(int u) {
        int i, v;
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;
            if (!check[v]) {
                check[v] = true;
                if (match[v]==-1 || dfs(match[v])) {
                    match[v] = u;
                    match[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    
    // 返回匹配个数  匹配结果存储在matching中  
    int GetAns(int n) {
        int ans = 0;
        memset(match, -1, sizeof(match));
        for (int i=1; i<=n; ++i) {  // i是从一个匹配集合开始for的,(左边集合 或者 右边集合.) 
            if (match[i] == -1) {
                memset(check, 0, sizeof(check));
                ans += dfs(i);
            }
        }
        return ans;
    }

    bfs写法

    int match[128];   // 匹配的边   
    int   vis[128];  // 注意是int类型 
    int prevv[128]; //  
    
    int bfs(int m) {
        queue<int> Q;
        int i, j, u, v, ans = 0;
        memset(match, -1, sizeof(match));
        memset(vis, -1, sizeof(vis));
        for (i=1; i<=m; ++i) {
            if (match[i] == -1) {
                while (!Q.empty()) Q.pop();
                Q.push(i);
                prevv[i] = -1;
                bool flag = false;
                while (!Q.empty() && !flag) {
                    u = Q.front();
                    for (j=head[u]; j && !flag; j=edge[j].lst) {
                        v = edge[j].to;
                        if (vis[v] != i) {
                            vis[v] = i;
                            Q.push(match[v]);
                            if (match[v] >= 0) {
                                prevv[match[v]] = u;
                            } else {
                                flag = true;
                                int d = u, e = v;
                                while (d != -1) {
                                    int t = match[d];
                                    match[d] = e;
                                    match[e] = d;
                                    d = prevv[d];
                                    e = t;
                                }
                            }
                        }
                    }
                    Q.pop();
                }
                if (match[i] != -1) ans++;
            }
        }
        return ans;
    } 

    同时bfs优于dfs,但是dfs好理解.

    附上学习的博客  : http://www.renfei.org/blog/bipartite-matching.html

    然后附上一些性质

    补充定义和定理:

    最大匹配数:最大匹配的匹配边的数目

    最小点覆盖数:选取最少的点,使任意一条边至少有一个端点被选择

    最大独立数:选取最多的点,使任意所选两点均不相连

    最小路径覆盖数:对于一个 DAG(有向无环图),选取最少条路径,使得每个顶点属于且仅属于一条路径。路径长可以为 0(即单个点)。

    定理1:最大匹配数 = 最小点覆盖数(这是 Konig 定理)

    定理2:最大匹配数 = 最大独立数

    定理3:最小路径覆盖数 = 顶点数 - 最大匹配数

    百科说: 最大匹配数=最大流=最小割=最小点集覆盖

    有向无环图的最大匹配数.

    https://vjudge.net/problem/HDU-1151  

    const int maxn = 100024;
    struct nobe {
        int to;
        int lst;
    }edge[maxn];
    int head[128];
    int qsz = 1;
    
    inline void add(int u, int v) {
        edge[qsz].lst = head[u];
        edge[qsz].to  = v;
        head[u] = qsz++;    
    }
    
    int  match[128];
    int  vis[128];
    
    bool dfs(int u) {
        int i, v;
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;
            if (vis[v]) continue;
            vis[v] = true;
            if (match[v]==-1 || dfs(match[v])) {
                match[v] = u;
                return true;
            }
        }    
        return false;
    }
    
    int main()
    {
        int t, n, m, i;
        scanf("%d", &t);
        while (t--) {
            memset(head, 0, sizeof(head));
            scanf("%d%d", &n, &m);
            int u, v;
            while (m--) {
                scanf("%d%d", &u, &v);
                add(u, v);
            }     
            int res = 0;
            memset(match, -1, sizeof(match));
            for (i=1; i<=n; ++i) {
                memset(vis, 0, sizeof(vis));
                res += dfs(i);
            }
            printf("%d
    ", n - res);
        }
    
        return 0;
    }

    无向图的最大匹配数.

    https://vjudge.net/problem/HihoCoder-1122

    int  match[10024];
    bool   vis[10024];
    
    bool dfs(int u) {
        int i, v;
        for (i=head[u]; i; i=edge[i].lst) {
            v = edge[i].to;
            if (!vis[v]) {
                vis[v] = true;
                if (match[v]==-1 || dfs(match[v])) {
                    match[v] = u;
                    match[u] = v;
                    return true;
                }
            }
        }
        return false;
    }
    
    int main()
    {
        int u, v, i, n, m;
        scanf("%d%d", &n, &m);
        while (m--) {
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u); // 双向边. 听说有些情况是要答案除以2的
        }
        
        int res = 0;
        memset(match, -1, sizeof(int) * (n + 10));
        for (i=1; i<=n; i++) {
            memset(vis, 0, sizeof(int) * (n + 10));        
            if (match[i] == -1) res += dfs(i);
        }
        printf("%d
    ", res);
        
        return 0;
    }
  • 相关阅读:
    易语言软件加VMProtect壳的正确方法
    ghost系统到硬盘完后,重启进入winxp安装的画面变成了蓝屏
    万象客户端设置服务端ip保存在注册表的位置
    php乱码解决
    远程桌面Default.rdp 中各个参数的含义
    关闭自动检测磁盘
    关于collapsed margin(外边距合并)
    position定位
    grunt-replace和grunt-include-replace问题
    关于动态生成dom绑定事件失效的原因
  • 原文地址:https://www.cnblogs.com/cgjh/p/9516001.html
Copyright © 2011-2022 走看看