二分图
二分图
什么是二分图
如果一个图中的点可以被分成两个部分,且每一个部分之间没有点相连,那么这就是一个二分图,如下:
可以发现,如果图中有长度为奇数的环(奇环),那么这一定不是一个二分图,如下:
关于二分图的一些基本概念
二分图的辨别及建图
由定义可知:二分图中直接相连的点被分在两边。所以可以对其进行染色。
int color[maxn + 5];
bool paint(int u,int col) { // bool: false->不是二分图
if (col[u] != 0) return col[u] == col; // 同一个点被染成不同的颜色->非二分图
col[u] = col;
bool flag = true;
for (auto v : G0[u]) flag &= paint(v,3 - col); // 1/2染色
return flag;
}
染色后从颜色 \(1\) 连向 \(2\) :
int cnt1 = 0,cnt2 = 0; // 颜色1/2的数量
for (int u = 1;u <= n;u ++) {
if (color[u] == 1) cnt1 ++;
else cnt2 ++;
}
int num = (cnt1 <= cnt2 ? 1 : 2); // (细节)从少数点连向多数点
for (int u = 1;u <= n;u ++) {
if (coler[u] == num) {
}
}
细节
- 使左侧点小于右侧点:在匈牙利算法中,左侧 \(n\) 个点会枚举完,但右侧 \(m\) 个点不会,所以实际时间复杂度为 \(O(nm')\)\((m'\le m)\)。
最大匹配数
选取最多的边,使得每个点只被选到不超过 \(1\) 次,则称选边数为最大匹配数。
匈牙利算法
假设从左向右匹配:对于左侧的一个点 \(u_1\) ,向右侧与它相连的每一个点进行尝试匹配(假设当前尝试点为 \(v\))。
-
如果 \(v\) 也没有被匹配,那就直接标记,答案增加。
(\(1\) 直接找到 \(2\) 匹配,\(2\) 直接找到 \(4\) 匹配)
-
如果 \(v\) 被匹配了,且匹配 \(v\) 的点是 \(u_2\) ,那就考虑让 \(u_2\) 换一个点,给 \(u_1\) 空出位置 。
(\(2\) 想找 \(3\) 匹配,但是 \(3\) 已经被匹配了,所以 \(1\) 改为匹配 \(4\) ,给 \(2\) 让出位置)
时间复杂度分析:
假设左侧 \(n\) 个点,右侧 \(m\) 个点:
对于 \(n\) 个点中的每一个点都会尝试最多 \(m\) 次,所以理论时间复杂度为 \(O(nm)\)
实际上,在绝大多数情况下,这 \(m\) 个点不会全部都被搜索
代码及实现细节
int vis[maxn + 5];
int p[maxn + 5]; // 右侧点 v 被左侧点 p[v] 匹配
bool dfs(int u,int tar) { // 左侧点 u 点能否匹配到右侧的某一个点
for (auto v : G[u]) {
if (vis[v] == tar) continue; // 标记叠加(细节1)
vis[v] = tar;
if (p[v] == 0 || dfs(p[v],tar)) { // 对方没有被匹配/对方的匹配对象可以切换到其它的点
p[v] = u;
return true; // 匹配成功
}
}
return false;
}
int main() {
...
int ans = 0;
for (int i = 1;i <= n;i ++) { ans += dfs(i,i); // 能匹配到就增加答案
}
return 0;
}
细节
- 采用标记叠加:如果每一次都清空标记数组,那么时间复杂度会是标准的 \(O(nm)\)
- 建图可以建单向边(前提是这个图确定是二分图且明确左右侧各点):可以发现,
dfs中只枚举了从左向右的边
最小点覆盖
选取最少的点,使得每一条边的两个端点至少有 \(1\) 个点被选取
显然,最小点覆盖 \(=\) 最大匹配数
最大独立集
选取最多的点,使得每一个点都互不直接连接,则称这样的点集为最大独立集
可以发现,每一个匹配所对应的两个点只能选取一个,所以答案为:总点数 \(-\) 最大匹配数
二分图中的最大团
最大团:一个点集,使得由该点集诱导的图为完全图。
由定义知:每一个点都相连。
反过来就是每一个点都不相连,即最大独立集。
所以:最大团 \(=\) 补图的最大独立集
例题
二分图理论很简单,重点在于如何将问题转化为二分图问题。
【HEOI2012】朋友圈
题目描述
在很久很久以前,曾经有两个国家和睦相处,无忧无虑的生活着.
一年一度的评比大会开始了,作为和平的两国,一个朋友圈数量最多的永远都是最值得他人的尊敬,所以现在就是需要你求朋友圈的最大数目.两个国家看成是 AB 两国,现在是两个国家的描述:
- A 国:每个人都有一个友善值,当两个 A 国人的友善值 \(a,b\),如果 \((a\mathbin{\mathrm{xor}} b) \bmod 2=1\),那么这两个人都是朋友,否则不是;
- B 国:每个人都有一个友善值,当两个 B 国人的友善值 \(a,b\),如果 \((a\mathbin{\mathrm{xor}} b) \bmod 2=0\) 或者 \((a\mathbin{\mathrm{or}} b)\) 化成二进制有奇数个 \(1\),那么两个人是朋友,否则不是朋友.
A、B 两国之间的人也有可能是朋友,数据中将会给出 A、B 之间「朋友」的情况.
对于朋友的定义,关系是是双向的.
在 AB 两国,朋友圈的定义:一个朋友圈集合 \(S\),满足 \(S \subset A \cup B\),对于所有的 \(i,j \in S\),\(i\) 和 \(j\) 是朋友.
观察两国的人分别如何才能成为朋友:
- A国:只观察二进制末位,可以发现如果两人要成为朋友,那么需要一奇一偶,从而推出A国只能选 \(0\),\(1\),\(2\) 个数。
- B国:稍微复杂,但可以发现,B国构成的补图是二分图
所以解法是:枚举 A国 的朋友,在 B国补图 中对与 A国相连的点求最大独立集

浙公网安备 33010602011771号