📜  最大匹配的 Hopcroft–Karp 算法第 2 组(实施)(1)

📅  最后修改于: 2023-12-03 14:55:19.126000             🧑  作者: Mango

最大匹配的 Hopcroft–Karp 算法第 2 组(实施)

简介

Hopcroft–Karp 算法是一种算法,用于在二分图中寻找最大匹配。这是一种增量方法,其时间复杂度为 $O(E \sqrt{V})$。

算法思想

Hopcroft–Karp 算法本质上是一个 BFS(广度优先搜索)算法,每次 BFS 都会沿着交替路找到一条增广路。Hopcroft–Karp 算法有两个阶段:第一阶段找到初始匹配和交替路径图;第二阶段寻找最大匹配。

Hopcroft–Karp 算法可以分类为增量算法(incremental algorithms)或增加路径算法(augmenting path algorithm)。

实现

下面是一个基于 Hopcroft–Karp 算法的实现。这个实现使用了 C++ 语言。此处的代码只包含了第二阶段的实现,因为第一阶段的实现比较简单。

const int MAXN = 100005;
const int MAXM = 500005;
const int INF = 0x3f3f3f3f;

struct edge {
    int v, nxt;  // v 是边指向的点的编号,nxt 则是下一条与 u 相连的边的编号 
} e[MAXM << 1];
int tot = 1, head[MAXN], dis[MAXN], match[MAXN], n, m, s, t;  // head 存储链式前向星连接表的表头,dis 数组记录到源点的距离,match 记录每个点已匹配的对象的编号 

void add(int u, int v) {  // 向链式前向星的连接表中添加一条从 u 到 v 的边 
    e[++tot] = edge{v, head[u]};
    head[u] = tot;
}

bool bfs() {  // 重构交替路 
    queue<int> q;
    memset(dis, INF, sizeof(dis));  // 初始化距离数组 
    for (int i = 1; i <= n; ++i)
        if (match[i] == 0) {
            dis[i] = 0;  // 将源点添加到队列中,并把距离设为 0 
            q.push(i);
        }
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int i = head[u]; i; i = e[i].nxt) {
            int v = e[i].v;
            if (dis[match[v]] == INF) {  // 如果该点所匹配的点未被访问过,则加入队列 
                dis[match[v]] = dis[u] + 1;
                q.push(match[v]);
            }
        }
    }
    return dis[t] != INF;  // 如果汇点的距离被更新了,则找到到达汇点的一条增广路 
}

bool dfs(int u) {  // 查找交替路 
    if (u == t)
        return true;
    for (int i = head[u]; i; i = e[i].nxt) {  // 枚举与 u 相连的点 
        int v = e[i].v;
        if (dis[match[v]] == dis[u] + 1 && dfs(match[v])) {  // 如果它所匹配的点在增广路上没出现过,则加入 
            match[u] = v;
            match[v] = u;
            return true;
        }
    }
    dis[u] = INF;  // 如果该点无法到达汇点,则把它到源点的距离设为 INF(表示已遍历) 
    return false;
}

int hopcroft_karp() {
    int res = 0;
    while (bfs())  // 只要存在增广路,就重构交替路 
        for (int i = 1; i <= n; ++i)
            if (match[i] == 0 && dfs(i))  // 只要已经匹配的边没有与之关联的交替路,就把这条边加入到交替路里 
                ++res;
    return res;
}
总结

Hopcroft–Karp 算法是求一个二分图最大匹配的经典算法,虽然其时间复杂度只为 $O(E\sqrt{V})$,但由于其难以实现以及空间复杂度等问题,实际应用不太广泛。