• 二分图匹配


    二分图的概念

    二分图又称作二部图,是图论中的一种特殊模型。设(G=(V,E))是一个无向图,如果顶点(V)可分割为两个互不相交的子集((A,B)),并且图中的每条边((i,j))所关联的两个顶点i和j分别属于这两个不同的顶点集((i in A,j in B)),则称图(G)为一个二分图。
    二分图
    上图是一个标准的二分图。

    最大匹配

    最大匹配即是选择其中边数最大的子集的图。
    二分图匹配主要有两种算法:匈牙利算法和使用dinic的二分图匹配

    匈牙利算法

    建立有向图(G),分为二分图的左侧和右侧。
    优先选择左侧序号更小的连接可能的边。
    对于两个点的目标点“冲突”的时候,采取“协商”的办法。
    即序号小的连接可能连接的另一条边。
    若“协商”失败,则放弃序号较大的点的边。
    一个寻找增广路的过程
    复杂度(o(n*m)) (n)为点数,(m)为边数

    使用Dinic的二分图匹配

    建立超级源点和超级汇点,使得源点与所有左侧点连接并权值为1,汇点与所有右侧点连接并权值为1,计算从超级源点到超级汇点的最大流就是最大匹配
    复杂度(o(nsqrt{m}))

    模版

    洛谷模版

    匈牙利算法版

    #include <bits/stdc++.h>
    using namespace std;
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #define de(a) cout << #a << " = " << a << endl
    #define rep(i, a, n) for (int i = a; i <= n; i++)
    #define per(i, a, n) for (int i = n; i >= a; i--)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    typedef pair<double, double> PDD;
    typedef vector<int, int> VII;
    #define inf 0x3f3f3f3f
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MAXN = 2e3 + 7;
    const ll MAXM = 2e6 + 7;
    const ll MOD = 1e9 + 7;
    const double eps = 1e-6;
    const double pi = acos(-1.0);
    struct edge
    {
        int to, nxt;
    } e[MAXM];
    int n, m, num, cnt = -1, head[MAXN], match[MAXN];
    bool f[MAXN];
    void add(int from, int to)
    {
        e[++cnt].to = to;
        e[cnt].nxt = head[from];
        head[from] = cnt;
    }
    bool hungarian(int u)
    {
        for (int i = head[u]; i != -1; i = e[i].nxt)
        {
            int v = e[i].to;
            if (!f[v])
            {
                f[v] = 1;
                if (!match[v] || hungarian(match[v]))
                {
                    match[v] = u;
                    return 1;
                }
            }
        }
        return 0;
    }
    void init()
    {
        memset(head, -1, sizeof(head));
        cnt = -1;
    }
    int main()
    {
        /*    freopen("k.in", "r", stdin);
        freopen("k.out", "w", stdout); */
        init();
        cin >> n >> m >> num;
        while (num--)
        {
            int u, v;
            cin >> u >> v;
            if (u > n || v > m)
                continue;
            add(u, v);
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            memset(f, 0, sizeof(f));
            if (hungarian(i))
                ans++;
        }
        cout << ans << endl;
        return 0;
    }
    

    Dinic版

    #include <bits/stdc++.h>
    using namespace std;
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #define de(a) cout << #a << " = " << a << endl
    #define rep(i, a, n) for (int i = a; i <= n; i++)
    #define per(i, a, n) for (int i = n; i >= a; i--)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    typedef pair<double, double> PDD;
    typedef vector<int, int> VII;
    #define inf 0x3f3f3f3f
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MAXN = 2e3 + 7;
    const ll MAXM = 2e6 + 7;
    const ll MOD = 1e9 + 7;
    const double eps = 1e-6;
    const double pi = acos(-1.0);
    int cnt = -1, head[MAXM], dis[MAXN], cur[MAXM];
    struct edge
    {
        int to, value, net;
    } e[MAXM << 1]; ///共有n*2条边
    void add(int from, int to, int value)
    { ///链式前向星
        cnt++;
        e[cnt].to = to;
        e[cnt].value = value;
        e[cnt].net = head[from];
        head[from] = cnt;
    }
    int bfs(int st, int ed)
    { ///建立层次图
        queue<int> que;
        memset(dis, -1, sizeof(dis));
        dis[st] = 0;
        que.push(st);
        while (!que.empty())
        {
            int x = que.front();
            que.pop();
            for (int i = head[x]; i > -1; i = e[i].net)
            {
                int now = e[i].to;
                if (dis[now] == -1 && e[i].value)
                {
                    que.push(now);
                    dis[now] = dis[x] + 1;
                }
            }
        }
        return dis[ed] != -1;
    }
    int dfs(int x, int t, int maxflow)
    {
        if (x == t)
            return maxflow;
        int ans = 0;
        for (int i = cur[x]; i > -1; i = e[i].net)
        { ///当前弧优化
            int now = e[i].to;
            if (dis[now] != dis[x] + 1 || e[i].value == 0 || ans >= maxflow)
                continue;
            cur[x] = i;
            int f = dfs(now, t, min(e[i].value, maxflow - ans));
            e[i].value -= f;
            e[i ^ 1].value += f; ///反向边加流量
            ans += f;
        }
        if (!ans)
            dis[x] = -1; ///炸点优化
        return ans;
    }
    int Dinic(int st, int ed)
    {
        int ans = 0;
        while (bfs(st, ed))
        {
            memcpy(cur, head, sizeof(head));
            int k;
            while ((k = dfs(st, ed, inf)))
                ans += k;
        }
        return ans;
    }
    void init()
    {
        cnt = -1;
        memset(head, -1, sizeof(head));
    }
    int main()
    {
        init();
        int n, m, ee;
     /*    freopen("k.in", "r", stdin);
        freopen("k.out", "w", stdout); */
        scanf("%d%d%d", &n, &m, &ee);
        int s = n + m + 1, t = n + m + 2; //超级源点 超级汇点
        for (int i = 1; i <= n; i++)
        {
            add(s, i, 1);
            add(i, s, 0);
        }
        for (int i = 1; i <= m; i++)
        {
            add(i + n, t, 1);
            add(t, i + n, 0);
        }
        while (ee--)
        {
            int u, v, t;
            scanf("%d%d", &u, &v);
            /* 数据有坑 */
            if (v > m || u > n)
                continue;
            v += n;
            add(u, v, 1);
            add(v, u, 0);
        }
        printf("%d
    ", Dinic(s, t));
        return 0;
    }
    
  • 相关阅读:
    'Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set.
    flask os.environ 的作用
    flask 中xx.init_app(app)方法
    win10安装ubuntu双系统遇到的问题
    福大软工 · 最终作业
    福大软工 · 第十二次作业
    Beta 冲刺(7/7)
    Beta 冲刺(6/7)
    常用正则
    使用elementUI动态增减表单项 且 使用自定义校验
  • 原文地址:https://www.cnblogs.com/graytido/p/11386063.html
Copyright © 2020-2023  润新知