zoukankan      html  css  js  c++  java
  • 二分图匹配

    1. 过山车

    题目链接:hdu - 2063

    题意:求二分图的最大匹配

    思路:二分图最大匹配模板题,利用匈牙利算法解决,其核心是通过不停地找增广路来增加匹配中的匹配边和匹配点,找不到增广路时,达到最大匹配

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 1010;
    
    struct node {
        int to, nex;
    };
    
    node edge[N * N];
    int k, n, m, used[N], nex[N];
    int cnt, head[N];
    
    void add_edge(int u, int v)
    {
        edge[++cnt].to = v;
        edge[cnt].nex = head[u];
        head[u] = cnt;
    }
    
    bool find(int u)
    {
        for (int i = head[u]; 0 != i; i = edge[i].nex) {
            int v = edge[i].to;
            if (!used[v]) {
                used[v] = 1;
                if (nex[v] == 0 || find(nex[v])) {
                    nex[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int match()
    {
        int res = 0;
        for (int i = 1; i <= n; i++) {
            memset(used, 0, sizeof(used));
            if (find(i)) res++;
        }
        return res;
    }
    
    int main()
    {
        while (scanf("%d", &k) && k) {
            cnt = 0;
            memset(head, 0, sizeof(head));
            memset(nex, 0, sizeof(nex));
            scanf("%d%d", &n, &m);
            while (k--) {
                int u, v;
                scanf("%d%d", &u, &v);
                add_edge(u, n + v);
            }
            printf("%d
    ", match());
        }
        return 0;
    }
    View Code

    2. Antenna Placement

    题目链接:poj - 3020

    题意:在平面上有若干点,可以用一个圆圈覆盖相邻的两个点,问最少需要多少圆圈能将所有点覆盖

    思路:二分图求最小路径覆盖,关键在于如何建图,可以采用黑白相间染色的办法,被染成黑色的点放在一个集合,被染成白色的点放在另一个集合,将相邻的黑色点和白色点之间连一条边,求出最大匹配数,二分图最小路径覆盖数=点的总数-二分图最大匹配数

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int N = 50;
    const int M = 410;
    
    struct node {
        int nex, to;
    };
    
    int T, h, w, n, m, b[N][N];
    int used[M], nex[M], head[M], cnt;
    node edge[M * M];
    char s[N][N];
    
    void add_edge(int u, int v)
    {
        edge[++cnt].to = v;
        edge[cnt].nex = head[u];
        head[u] = cnt;
    }
    
    bool find(int u)
    {
        for (int i = head[u]; 0 != i; i = edge[i].nex) {
            int v = edge[i].to;
            if (used[v]) continue;
            used[v] = 1;
            if (0 == nex[v] || find(nex[v])) {
                nex[v] = u;
                return true;
            }
        }
        return false;
    }
    
    int match()
    {
        int res = 0;
        for (int i = 1; i <= n; i++) {
            memset(used, 0, sizeof(used));
            if (find(i)) res++;
        }
        return res;
    }
    
    void init()
    {
        cnt = 0;
        memset(nex, 0, sizeof(nex));
        memset(head, 0, sizeof(head));
        memset(b, 0, sizeof(b));
    }
    
    int main()
    {
        scanf("%d", &T);
        while (T--) {
            init();
            scanf("%d%d", &h, &w);
            for (int i = 1; i <= h; i++) scanf("%s", s[i] + 1);
            n = m = 0;
            for (int i = 1; i <= h; i++) {
                for (int k = 1; k <= w; k++) {
                    if ('*' != s[i][k]) continue;
                    if (0 == (i + k) % 2) b[i][k] = ++n;
                    else b[i][k] = ++m;
                }
            }
            for (int i = 1; i <= h; i++) {
                for (int k = 1; k <= w; k++) {
                    if ('*' != s[i][k] || 0 != (i + k) % 2) continue;
                    if (b[i - 1][k]) add_edge(b[i][k], n + b[i - 1][k]);
                    if (b[i + 1][k]) add_edge(b[i][k], n + b[i + 1][k]);
                    if (b[i][k + 1]) add_edge(b[i][k], n + b[i][k + 1]);
                    if (b[i][k - 1]) add_edge(b[i][k], n + b[i][k - 1]);
                }
            }
            int res = match();
            printf("%d
    ", n + m - res);
        }
        return 0;
    }
    View Code

    3. Treasure Exploration

    题目链接:poj - 2594

    题意:给出一个由n个点m条边组成的有向无环图,求最少需要多少路径,使得这些路径可以覆盖所有点,每个点可以被多条路径覆盖

    思路:二分图求最小路径覆盖,因为有的点可以被多条路径覆盖,可能存在相交路径,所以先要用floyd求出传递闭包,将求最小可相交路径转换成最小不可相交路径,然后再用二分图求最小路径覆盖,最小路径覆盖数=点的总数-二分图最大匹配数

    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cstdio>
    
    using namespace std;
    
    const int N = 510;
    
    int n, m, f[N][N];
    int used[N], nex[N];
    
    void floyd()
    {
        for (int k = 1; k <= n; k++)
            for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                    f[i][j] |= (f[i][k] & f[k][j]);
    }
    
    bool find(int u)
    {
        for (int i = 1; i <= n; i++) {
            if (!used[i] && f[u][i]) {
                used[i] = 1;
                if (0 == nex[i] || find(nex[i])) {
                    nex[i] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int match()
    {
        int res = 0;
        for (int i = 1; i <= n; i++) {
            memset(used, 0, sizeof(used));
            if (find(i)) res++;
        }
        return res;
    }
    
    int main()
    {
        while (scanf("%d%d", &n, &m) && 0 != (n + m)) {
            memset(nex, 0, sizeof(nex));
            memset(f, 0, sizeof(f));
            while (m--) {
                int u, v;
                scanf("%d%d", &u, &v);
                f[u][v] = 1;
            }
            floyd();
            int res = match();
            printf("%d
    ", n - res);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    MySQL中内存分为全局内存和线程内存
    mysql 线程级别的缓冲区
    MySQL Handler变量解析
    HANDLER命令与实现
    MySQL Spatial Extensions 地理信息
    C++中临时对象的学习笔记
    HDC与CDC相互转换
    B树
    基于R-Tree的最近邻查询
    地图发布的几种服务的区别
  • 原文地址:https://www.cnblogs.com/zzzzzzy/p/12668023.html
Copyright © 2011-2022 走看看