二分图学习笔记(二分图判定及二分图最大匹配)
作者:互联网
二分图判定
定理:一张无向图是二分图,当且仅当途中不存在奇环(长度为奇数的环)。
依据此定理,我们可以用染色法进行二分图的判定。大致思想为:尝试用黑白(c = 0或1)两种颜色标记图中的结点。当一个节点被标记后,它的所有相邻节点被标记为与它相反的颜色(c ^ 1)。若标记过程中产生冲突,则说明图中存在奇环。实现代码如下:
点击查看代码
inline bool dfs(int cur, int c) {
colour[cur] = c;
for (int i = head[cur]; i; i = nxt[i]) {
if (colour[to[i]] == -1) {
if (dfs(to[i], c ^ 1) == 1)
return 1;
}
else if (colour[to[i]] == c)
return 1;
}
return 0;
}
时间复杂度为O (N + M)
二分图最大匹配
“任意两条边都没有公共端点”的边的集合被称为图的一组匹配。在二分图中,包含边数最多的一组匹配被称为二分图的最大匹配。如果在二分图中存在一条连接两个非匹配点的路径 path, 使得非匹配边与匹配边在 path 上交替出现,那么撑 path 就是这张二分图的增广路。
显而易见,增广路具有两条性质:
- 长度 len 是奇数。
- 路径上第1、3、5、……、len条边是非匹配边,第2、4、6、……、len - 1 条边是匹配边,即匹配边与非匹配边交替出现。
由第二条性质可知,二分图的一组匹配 S 是最大匹配,当且仅当图中不存在 S 的增广路。证明:
反证法: 假设对于二分图的最大匹配 S,图中存在 S 的增广路。
由性质二可知:将增广路上的边取反(原先的匹配边变为非匹配边,原先的非匹配边变为匹配边),则新得到的边集 S' 仍然是一组匹配,且匹配边数比 S 增加了1。故假设不成立。
证毕。
匈牙利算法(增广路算法、月老算法)
匈牙利算法用于计算二分图的最大匹配,其核心思想为不断寻找增广路,并将找到的增广路取反。匈牙利算法的关键也正是在于如何找到一条增广路。代码如下:
点击查看代码
inline bool find(int x) {
for (int i = head[x]; i; i = nxt[i]) {
int j = to[i];
if (mark[j] == 0) {
mark[j] = 1;
if (match[j] == 0 || find(match[j]) == 1) {
match[j] = x;
return 1;
}
}
}
return 0;
}
for (int i = 1; i <= n1; i++) { // 在main函数中
memset(mark, 0, sizeof(mark));
if (find(i) == 1)
ans++;
}
整个实现过程中似乎并没有寻找增广路的过程,但我们经过思考后可以发现,当左部点 x 进行匹配时,有这么两种可能:
- 右部点 y 本身就是非匹配点,此时无向边(x, y ) 本身就是非匹配边,自己能够给构成一条长度为1的增广路。
- 右部点 y 已经与左部点 x' 匹配,但如果从 x'出发能够找到另一个未匹配的右部点 y' 与之相匹配,则路径 x ~ y ~ x' ~ y' 为一条增广路。
如果找不到那就算了
匈牙利算法再是显示采用深搜的框架,递归的从 x 出发寻找增广路。若找到,则在回溯是,中号可以吧路径上的匹配状态取反。另外,可以用全局的 bool 数组标记右部点的访问情况,以防重复搜索。
匈牙利算法的正确性基于贪心策略,即:当一个节点成为匹配点后,最多因找到增广而更换匹配对象,但绝不会再次变回非匹配点。
最后,对于每个左部节点,寻找增广路最多遍历整张二分图一次。因此,匈牙利算法的时间复杂度最差为 O(NM),实际情况下一般远低于 O(NM)
标签:二分,匹配,增广,int,笔记,算法,判定,return 来源: https://www.cnblogs.com/Nebula-Astraea/p/15977806.html