交互式图论学习
交互式图论学习
Guest User
Using app without sign in
二分图检查器
确定图是否可以用两种颜色着色
选择算法并生成步骤以开始可视化
当图的顶点可分为两组、每条边都跨组连接而绝不在同一组内时,该图是二部图。检查二部性等价于测试图能否用两种颜色着色,或图是否不含奇数长度的环。
BFS 或 DFS 遍历会即时用两色为图着色:给起始顶点着色,再给每个被发现的邻居着相反的颜色。若某条边连接了两个同色顶点,则存在奇环,图不是二部图。每个分量都必须检查。测试运行在 O(V + E)。
二部结构是匹配问题的基础:把学生分配到学校、任务分配到机器、乘客匹配到司机。推荐系统将用户和物品建模为二部图的两侧。基于奇环的刻画是常见的面试热身题,会引出最大匹配主题。
一个图是二分图,当且仅当它可以用两种颜色着色。因此这项检测就是一次遍历:把每个结点染成与其父结点相反的颜色,并留意是否出现冲突。
是否二分图(图):
颜色 = {} // 所有结点均未着色
对每个尚未着色的结点 s: // 覆盖每个分量
颜色[s] = 0
队列 = [s]
当队列非空时:
u = 队列.取出()
对 u 的每个邻居 v:
若 v 尚未着色:
颜色[v] = 1 - 颜色[u]
队列.放入(v)
否则若 颜色[v] == 颜色[u]:
返回 假 // 发现奇环
返回 真这个冲突并不是一个随意的失败信号,而是一份证明。若两个相邻结点被染上同一种颜色,那么从它们各自沿树边回到最近公共祖先的两条路径,再加上这条连接边,就构成了一个奇数长度的环。二分图恰恰就是不含奇环的图,因此这条冲突边是一份可以交还给调用方的凭证。
先给一个四元环做二着色,再加入一条弦,看同一次遍历如何把它判否。
示例图: 先是四元环 A-B、B-C、C-D、D-A。随后是同一个图再加上弦 A-C。
四元环是二分图,两部分为 {A, C} 与 {B, D};加入弦 A-C 后它不再是二分图,冲突在边 B-C 处被检出。请注意它所展示的一般规律:所有偶环都是二分的,所有奇环都不是,因此单凭环的长度就能决定结果。另外也请注意,冲突是在边 B-C 上报告的,而不是在那条弦本身上,这是正常的,因为算法报告的是矛盾最先暴露的位置,而不是你会归咎的那条边。
时间: O(V + E) · 空间: O(V)
这是一次 BFS 或 DFS,每条边只做一次比较,因此代价恰好等于一次遍历。每个结点着色一次,每条边从两个端点各检查一次。空间是每个结点一个颜色,再加上队列或递归栈,都是 O(V)。对所有结点的外层循环在渐进意义上不增加任何代价,而它正是让非连通图也能正确工作的关键。不存在更快的方法,因为判定二分性必须查看每一条边:任何一条未被检查的边都可能正是造出奇环的那一条。
二分性通常是一个前置条件而非目标。之后要做什么,取决于你当初为何要问这个问题。
| 替代算法 | 以下情况更合适 | 代价 |
|---|---|---|
| Hopcroft-Karp 算法 | 图确实是二分图,而你接下来想在两部分之间求最大匹配。 | O(E·sqrt(V)) |
| 图着色 | 图不是二分图,而你需要真正的色数,它至少为 3。 | 一般情形下 NP 困难 |
| 奇环检测 | 你要的是那个作祟的环本身,而不只是是或否。可在冲突边处借助 BFS 的父指针把它还原出来。 | O(V + E) |
| 带奇偶性的并查集 | 边是逐条到达的,而你希望在某条边刚加入、破坏二分性的那一刻就把它拒绝掉。 | O(E·α(V)) |