二分图的最大匹配

C++

二分图的最大匹配

/*
 * 二分图的最大匹配
 *
 * 先前在介绍二分图时候,我们简述了什么是二分图,以及二分图的充要条件,并学会使用了染色法来判断二分图。
 * 此次来介绍二分图的最大匹配。
 *
 * 定义:
 *      二分图的匹配:
 *          给定一个二分图 G,在 G 的一个子图 M 中,M 的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。
 *      二分图的最大匹配:
 *          所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
 * 二分图最大匹配算法:
 *      二分图最大匹配算法是基于暴力搜索的算法,同时又使用了 st 数组进行记忆化搜索,因而复杂度控制到了 O(NM)。
 *
 *      res = 0
 *      对集合 U 中的每一个点进行遍历
 *      for u in U:
 *          记忆化清空,集合 V
 *          memset(st, false, sizeof st)
 *          如果点 u 可以找到集合 V 中的点 v 相匹配 (这里匹配指的是 v 之前并未和其他点匹配过,
 *              或者之前和点 v 匹配的点 u' 可以找到集合中的 v' 配对 -> 这是一个递归的过程
 *              st 数组,优先剪枝,避免了环形循环)
 *              res += 1
 *      当然,这个 memset 是可以条件性优化的,因为当 u find 为 false 的时候,那么 之前 st 标记为 false 的点,仍旧是没有办法给他腾出一条边。
 *          u find = true, 才需要 memset(st, false, sizeof st)。
 *
 */
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;

const int N = 510, M = 100010;
int n1, n2, m;
int h[N], e[M], ne[M], idx;
int match[N];
bool st[N];


void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}

// 查看 u 能否在不减少 res 的条件下,多加一条边
bool Find(int u) {
    int v;
    for (int i = h[u]; ~i; i = ne[i]) {
        v = e[i];
        if (st[v] == false) {
            st[v] = true;
            if (match[v] == -1 || Find(match[v])) {
                match[v] = u;
                return true;
            }
        }
    }
    return false;
}

int main()
{
    // initialize
    memset(h, -1, sizeof h);
    memset(ne, -1, sizeof ne);
    memset(match, -1, sizeof match);
    idx = 0;

    // input
    scanf("%d%d%d", &n1, &n2, &m);
    while (m -- ) {
        static int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
    }

    // get the max match
    int res = 0;
    bool pre = true;
    for (int i = 1; i <= n1; i ++ ) {
        if (pre == true) {
            memset(st, false, sizeof st);
        }
        pre = Find(i);
        if (pre) {
            res += 1;
        }
    }

    printf("%d\n", res);
    return 0;
}
posted @ 2022-06-24 20:54  lucky_light  阅读(301)  评论(1编辑  收藏  举报