TonyYin's Blog

Back

二分图

定义

二分图

对于一个无向图 G=(V,E)G=(V, E),可以将 VV 分为两个不相交的子集,使得任意一条边的顶点分属两个不同的点集,那么这个无向图是二分图。

匹配

对于无向图 G=(V,E)G=(V, E),取边集的子集 EE^*,使得 EE^*任意两条边没有公共顶点,那么 EE^* 是图 GG 的一个匹配,又称边独立集。

最大匹配

边数最多的匹配。极大匹配的边数唯一,取法可能不唯一。

匹配边 & 非匹配边

在边独立集中的边是匹配边,反之是非匹配边。

匹配点 & 非匹配点

能被匹配边连接到的点是匹配点,反之是非匹配点。

完美匹配

MM 是图 GG 的一个匹配,且 GG 中的每个顶点都是匹配点,那么 MMGG 的完美匹配。

交错路径

GG 中,由匹配边和非匹配边交替构成的路径,是交错路径。

增广路径

起点和终点都是非匹配点的交错路径,是增广路径。

显然,MMGG 的最大匹配,当且仅当 GG 中不含关于 MM 的增广路径。

因为如果 GG 中含有关于 MM 的增广路径,把增广路径上的匹配边取反,可以使匹配大小增加11.

二分图最大匹配

概述

在二分图中找到一个最大匹配。

Hall定理

二分图 G=<V1,V2,E>G=<V_1, V_2, E>,其中 V1V2|V_1| \leq |V_2|,则 GG 中存在 V1V_1V2V_2 的完美匹配,当且仅当 V1V_1 中任意 k[1,V1]k\in [1, |V_1|] 个顶点,都至少与 V2V_2 中的 kk 个顶点相连。

反证即可。

思想

对一条增广路进行异或之后,能使匹配中的边数增加 11.

异或之后,可以得到:

匈牙利算法

  1. 将初始的匹配 MM 置为 \emptyset.
  2. 找到一条增广路径,通过异或操作更新最大匹配。
  3. 重复2.

时间复杂度O(EV)\mathcal{O}(EV)

代码(From Jisuanke):

const int MAX_N = 100;
const int MAX_M = 10000;
struct Edge {
    int v, next;
} e[MAX_M];
int p[MAX_N], eid;
void init() {
    memset(p, -1, sizeof(p));
    eid = 0;
}
void insert(int u, int v) {
    e[eid].v = v;
    e[eid].next = p[u];
    p[u] = eid++;
}
bool vst[MAX_N];
int rmatch[MAX_N];
bool dfs(int u) {
    for(int i = p[u]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if(!vst[v]) {
            vst[v] = true;
        	if(rmatch[v] == -1 || dfs(rmatch[v])) {
                rmatch[v] = u;
                return true;
            }
        }
    }
    return false;
}
int hungary(int n) {
    int cnt = 0;
    memset(rmatch, -1, sizeof(rmatch));
    for(int i = 1; i <= n; i++) {
        memset(vst, 0, sizeof(vst));
        cnt += dfs(i);
    }
    return cnt;
}
c
二分图 最大匹配 匈牙利算法
https://www.tonyyin.top/blog/oi-notes/bi-graph
Author TonyYin
Published at January 2, 2021
Comment seems to stuck. Try to refresh?✨