「笔记」二分图
二分图学习笔记
定义#
二分图又称二部图,是图论中的一种特殊模型,英文名叫 Bipartite graph。
二分图的节点由两个集合组成,且两个集合内部没有边。
百度的定义:
设G=(V,E)G=(V,E)是一个无向图,如果顶点VV可分割为两个互不相交的子集(A,B)(A,B),并且图中的每条边(i,j)(i,j)所关联的两个顶点ii和jj分别属于这两个不同的顶点集(iϵA,jϵB)(iϵA,jϵB),则称图GG为一个二分图。
先来看一个比较正常的二分图
这个二分图还是很正常的,一看就知道左右两边的两个圈分别代表了上面所说的两个集合,两个集合内部的点都没有连边
再来看看下面几个二分图
二分图1#
其实这个还算简单,并不难看出来是个二分图,转化一下子就变成了下面这个样子
再看一个:
二分图2#
这个长得也不像二分图,然后你拖着拖着他就变成了下面这个样子,没错它也是个二分图
再看一个
二分图3#
看到这个我的想法是:纳尼?这个是二分图!!
然而真香了,他的确是个二分图
还有很多看起来十分鬼畜的二分图,我就不一一列举了。这上面的几个二分图告诉我们:不要相信你看到的东西
性质#
- 如果两个集合中的点分别染成黑色和白色,可以发现二分图中的每一条边都一定是连接一个黑色点和一个白色点。
- 二分图不存在长度为奇数的环,如果一个图是二分图,那么它一定没有奇环,如果一个图没有奇环的话,那么它可以是二分图
因为每一条边都是从一个集合走到另一个集合,只有走偶数次才可能回到同一个集合
判定#
染色法:假设DFSDFS初始点AA涂黑色,与它相邻的节点就涂白色。如果搜到某个点uu的相邻点vv已经涂色并且与uu同色,就不可能是二分图了(找到了一个奇环)

相关概念#
匹配#
给定一个二分图GG,在GG的一个子图MM中,MM的边集{E}{E}中的任意两条边都不依附于同一个顶点,则称MM是一个匹配
最大匹配#
包含的边数最多的匹配
完美匹配#
所有的点都在匹配边上的匹配
最佳匹配#
如果GG为加权二分图,则权值和最大的完美匹配称为最佳匹配
二分图最大匹配求法#
- 匈牙利算法 O(nm)O(nm)
- HKHK算法O(√n∗m)O(√n∗m)
- 网络最大流
二分图多重匹配求法#
某些点可以被匹配多次
网络最大流
二分图最佳匹配求法#
- KMKM算法(优化版O(n3)O(n3))
- 网络最大流
匈牙利算法-求二分图最大匹配#
交替路#
从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边...形成的路径叫交替路。
增广路#
从一个未匹配点出发,走交替路,如果途径另一个未匹配点 (出发的点不算),则这条交替路称为增广路(agumenting pathagumenting path)
由增广路的定义可以推出下述三个结论#
- PP的路径长度必定为奇数,第一条边和最后一条边都不属于MM。
- PP经过取反操作可以得到一个更大的匹配M′M′。
- MM为GG的最大匹配当且仅当不存在相对于MM的增广路径。
算法轮廓:#
- 置MM为空
- 找出一条增广路径PP,通过取反操作获得更大的匹配M′M′代替MM
- 重复22操作直到找不出增广路径为止
时间复杂度:〇(nm)
/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int A = 1e5 + 11;
const int B = 1e6 + 11;
inline int read() {
char c = getchar(); int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
return x * f;
}
int n, m, match[A], E, vis[A], ans;
struct node { int to, nxt; } e[B];
int head[A], cnt;
inline void add(int from, int to) {
e[++cnt].to = to;
e[cnt].nxt = head[from];
head[from] = cnt;
}
bool dfs(int now) {
for(int i = head[now]; i; i = e[i].nxt) {
int to = e[i].to;
if(vis[to]) continue;
vis[to] = 1;
if(!match[to] || dfs(match[to])) {
match[to] = now;
return 1;
}
}
return 0;
}
int main() {
n = read(), m = read(), E = read();
for(int i = 1, x, y; i <= E; i++) {
x = read(), y = read();
if(x > n || y > m) continue;
add(x, y);
}
for(int i = 1; i <= n; i++) {
memset(vis, 0, sizeof(vis));
if(dfs(i)) ans++;
}
cout << ans << '\n';
return 0;
}
其他相关概念#
二分图最小顶点覆盖#
是指最少的顶点数使得二分图GG中的每条边都至少与其中一个点相连
二分图的最小顶点覆盖数=二分图的最大匹配数
有向无环图最小不相交路径覆盖#
也称为最小边覆盖,是指用尽里少的顶点不相交的简单路径覆盖二分图中的所有顶点
路径长度可以为00
二分图的最小路径覆盖数=|V||V|-二分图的最大匹配数
二分图最大独立集#
最大独立集是指寻找一个点集,使得其中任意两点在图中无对应边。
对于一般图来说,最大独立集是一个NPNP完全问题,对于二分图来说最大独立集 =|V||V|-二分图的最大匹配数。
作者:loceaner
出处:https://www.cnblogs.com/loceaner/p/12374669.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
简介:来自18线小县城的OIer一名,觉得写的还行的话就关注我吧!
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)