Appearance
二分图是一种特殊的图结构。
如果图 G 可以划分成两个点集
下文记顶点数为
判定
图 G 是 2- 着色的 图 G 是二分图。
容易证明,将点属于的集合
dfs 朴素染色即可,若出现相邻节点颜色相同则图不是二分图。每个点只会被染色一次,每条边只会被邻接表扫描常数次,所以时间复杂度为
点击展开代码
cpp
bool dfs(int x, int c) {
col[x] = c;
for (auto u : p[x]) {
if (!col[u]) {
if (!dfs(u, 3 - c))
return 0;
} else if (col[u] == c)
return 0;
}
return 1;
}
for (int i = 1; i <= n; i++) {
if (!col[i]) {
if (!dfs(i, 1)) {
cout << "No\n";
return;
}
}
}图 G 中不存在奇环 图 G 是二分图。
奇环无法二染色。对每个连通块建立一棵 dfs 生成树;删去所有非树边后,每个连通块是一棵树,整个图剩下的是生成森林,而不一定是一棵树。
对于一条非树边
反过来,若所有边的两个端点深度奇偶性都不同,那么直接按深度奇偶二染色即可。因此“不存在奇环”和“可以二染色”是等价的。
建立生成森林并扫描所有边,时间复杂度为
点击展开代码
cpp
// 维护 dfs 生成森林
for (int i = 1; i <= n; i++) {
for (auto u : p[i]) {
if (u == fa[i] || fa[u] == i)
continue;
if ((dep[u] & 1) == (dep[i] & 1)) {
// 存在奇环
return;
}
}
}扩展域并查集判二分图
从二分图定义出发,点集需要能被划分成两个集合。
那么对于一条边
使用扩展域并查集维护即可。
初始化
点击展开代码
cpp
for (auto [u, v] : edge) {
if (dsu.same(u, v) || dsu.same(u + n, v + n)) {
// 不能划分到两个集合中
return;
}
dsu.merge(u, v + n);
dsu.merge(u + n, v);
}使用扩展域并查集可以在线判断二分图。
应用
基于二分图的特殊性质,一些在一般图上比较困难的问题会变得相对容易。
1. 二分图最大匹配
匹配指一组边,图中每个点只出现在其中一条边中。
最大匹配指要求选出最多边。
求解:
一般情况下,使用匈牙利算法即可求二分图的最大匹配,时间复杂度:
注:极端情况下,二分图使用网络流算法 Dinic 求最大流,时间复杂度为
构造:
匈牙利算法可得最大匹配的一种可行方案。
2. 二分图最小点覆盖
最小点覆盖问题是指,在一张无向图中选择最少的顶点,满足每条边至少有一个端点被选。
求解:
一般图的最小点覆盖问题是 NP-hard 的。Kőnig 定理说明,在二分图上,最小点覆盖的大小等于最大匹配的大小,即
构造:
先求出一组最大匹配
不能从每条最大匹配边中任取一个端点;任意选择虽然恰好选出
3.二分图最大独立集
最大独立集问题是指,在一张无向图中选择最多的顶点,满足两两之间互不相邻。
求解:
最大独立集问题对于一般图是 NP-hard 的,在二分图上,最大独立集
构造:
取最小点覆盖补集。
4.有向无环图最小路径覆盖
最小路径覆盖问题是指,在一张有向图中,选择最少数量的简单路径,使得所有顶点都恰好出现在一条路径中。
一般的有向图上的最小路径覆盖问题是 NP-hard 的。
求解:
DAG 的最小不相交路径覆盖
构造:
5.有向无环图最小路径重复点覆盖
这里选择最少数量的路径覆盖所有点,但允许一个点出现在多条路径中。它与上一节“不重复经过顶点”的路径覆盖不是同一个问题。
求解:
记原图为
对
如果题目允许直接把“可达”视为一步,可以输出
使用 bitset 按逆拓扑序计算可达集合时,每条边可能触发一次长度为
其中
构造:
先根据最大匹配把
6. 二分图最大权匹配
二分图的最大权匹配是指二分图中边权和最大的匹配。若允许顶点不匹配,则空匹配也是合法方案,答案至少为
求解:
经典 KM 算法直接求解的是完全、等部二分图上的最大权完美匹配。设补全后两侧大小为
- 若要求原图的完美匹配,缺失边不能当成普通的
权边;应赋成不可选的负无穷,并在计算后验证答案没有使用缺失边。真实负权边可能被完美匹配强制选择。 - 若求允许不选边的任意大小最大权匹配,可以令
,用虚点补齐较小的一侧,并用权值为 的人工边补成完全图。真实负权边也可按 权人工选择处理;KM 得到完美匹配后,只保留其中被选中的真实正权边,其余人工边表示对应顶点未匹配。 - 若要求“先最大化匹配边数,再最大化权值”,则不能直接使用上一种
权补边方式,需要先求最大匹配数,或给每条真实边增加足够大的统一权值以固定第一目标。
构造:
根据 KM 得到的匹配数组恢复配对;使用虚点或人工边建模时,需要删去这些不对应原图实边的配对。
