二分图的概念
无向图 G = ( V , E ) G=(V,E) G=(V,E)的顶点集 V V V可分为两个集合 V 1 V_1 V1, V 2 V_2 V2, s . t . ∀ ( u , v ) ∈ E , ∃ u ∈ V 1 , v ∈ V 2 \: s.t. \: \forall (u,v) \in E, \: \exists \: u\in V_1,v \in V_2 s.t.∀(u,v)∈E,∃u∈V1,v∈V2 或 u ∈ V 2 , v ∈ V 1 u\in V_2,v \in V_1 u∈V2,v∈V1,则称图 G G G为二分图,即所有的边都位于 V 1 V_1 V1和 V 2 V_2 V2之间。
判断方法
判断二分图的常用方法为染色法。通过遍历整个无向图 G G G,对图中的顶点进行有规律的染色。
染色步骤为:选择一个起始顶点 u u u,将其染成黑色 B L A C K BLACK BLACK;然后遍历所有与 u u u相邻的顶点 v v v,将 v v v染成白色 W H I T E WHITE WHITE;同时再将与顶点 v v v相邻的顶点 w w w,将 w w w染成黑色 B L A C K BLACK BLACK;依次进行下去,直到遍历结束。
若图中还有顶点未遍历,则重复上述染色步骤。
如果我们能够完成染色步骤,那么该无向图为二分图。
如果染色过程中产生了冲突,即当遍历到某个顶点 x x x时,该顶点已经染色,并且 x x x的颜色与我们准备给其染成的颜色不一致,则表示该无向图不是二分图。
判断二分图的过程
可以使用深度优先搜索或广度优先搜索对无向图进行遍历。
考虑到无向图可能是一个非连通图,因此需要多次执行广度优先搜索或深度优先搜索才能完全遍历所有的顶点。
BFS Pseudocode
G = ( V , E ) G=(V,E) G=(V,E)
∀ \forall ∀ 顶点 u ∈ V u\in V u∈V,定义 v i s i t e d [ u ] visited[u] visited[u]存储搜索过程中顶点 u u u的染色情况:
U
N
V
I
S
I
T
E
D
UNVISITED
UNVISITED:未访问状态。
W
H
I
T
E
WHITE
WHITE:标记为白色。
B
L
A
C
K
BLACK
BLACK:标记为黑色。
定义First-in, first-out (FIFO)队列 Q Q Q,存放搜索中的顶点。
BFS-Pseudocode(G)
// 初始化顶点的颜色
for every u in V[G]
visited[u] = UNVISITED
//初始化队列
Q = nil
// 遍历无向图的全部顶点,进行染色
for every u in V[G]
if visited[u] == UNVISITED then
result = BFS(u)
do if result == false then
return false
return true
BFS(u)
// 开始搜索时设置源顶点u的颜色为BLACK,并放入队列中
Q.push(u)
visited[u] = BLACK
// Q队列存放搜索中的顶点;该顶点已被染色,但其邻接表的顶点还尚未被染色
while Q is not empty
do u = Q.pop()
for v in Adj[u] // 顶点u的邻接表
do if visited[v] == UNVISITED then // 对未访问的顶点染成与u相反的颜色
visited[v] = visited[u] == WHITE ? BLACK: WHITE
Q.push(v)
else if visited[u] == visited[v] then // 染色过程中产生了冲突
return false // 不是二分图
else then
trivial
return true
DFS Pseudocode
DFS-Pseudocode(G)
// 初始化顶点的颜色
for every u in V[G]
visited[u] = UNVISITED
// 判断结果
result = true
// 遍历无向图的全部顶点,进行染色
for every u in V[G]
if visited[u] == UNVISITED then
DFS(u, BLACK)
do if result == false then
return false
return true
DFS(u, color)
// 顶点u的染色为color
visited[u] = color
for v in Adj[u] // 顶点u的邻接表
do if visited[v] == UNVISITED then
// 对未访问的顶点染成与u相反的颜色
reverseColor = color == WHITE ? BLACK: WHITE
DFS(v, reverseColor)
do if result == flase then // 深度遍历过程中,提前判断,提前结束
return
else if color == visited[v] then // 染色过程中产生了冲突
result = false // 不是二分图
return
else then
trivial