1、题目描述
题目来自算法导论第3版22章的第7题,题目描述如下
职业摔跤选手可以分为两种类型:“娃娃脸”(好人)型和“高跟鞋”(“坏人”)型。在任意一对职业摔跤选手之间都可能存在竞争关系。假定有
n
n
n个职业摔跤手,并且有一个给出的竞争关系的
r
r
r对摔跤手的链表。请给出一个时间复杂度为
O
(
n
+
R
)
O(n+R)
O(n+R)的算法来判断是否可以将某些型"娃娃脸",而剩下的划分为"高跟鞋"型,使得所有的竞争关系均只存在于娃娃脸型和高跟鞋型选手之间。如果可以进行这种划分,则算法该如何设计。
2、问题分析
这个问题等价于判断一个图是不是二分图的问题,因为同类之间不可能有关系,而不同类之间可以存在关系。
用到的定理:一个图是二分图当且仅当图中所有回路都为偶数个顶点。
用到的方法:采用点着色的方法。
3、算法思路
- 初始化图
G
(
V
,
E
)
G(V,E)
G(V,E)顶点颜色为白色。
时间: O ( V ) O(V) O(V) - 初始队列
Q
Q
Q为空,随机选择一个顶点
s
s
s加入队列
Q
Q
Q,
s
s
s的颜色着为红色。
时间: O ( 3 ) O(3) O(3) - 执行如下循环,如果队列
Q
Q
Q不为空,从队列中弹出元素赋值给顶点
u
u
u,遍历
u
u
u的邻接链表(也可以是邻接矩阵),若链表非空,对于顶点
u
u
u中邻接矩阵的元素
v
v
v,如果
v
v
v的颜色是白色且
u
u
u的颜色是红色,那么将顶点
v
v
v着成蓝色;若
v
v
v的颜色是白色且
u
u
u的颜色是蓝色,那么将顶点
v
v
v着成红色;若顶点
u
u
u的颜色和顶点
v
v
v的颜色相同,那么直接break,表示该图不是二分图。在着色的过程,将顶点
v
v
v加入到队列
Q
Q
Q中。执行循环直到队列空为止。
时间: 队列出来元素 O ( V ) O(V) O(V),邻接链表遍历 O ( 2 E ) O(2E) O(2E),顶点颜色着色 O ( V ) O(V) O(V),顶点入队列 O ( V ) O(V) O(V) - 最终即可返回是否为二分图的信息。
4、伪代码
Judge(G,s) {
for each vertex u in V[G] - {s}
do color[u] <- white
color[s] <- red
Q <- empty
ENQUEUE(Q,S)
while Q != empty
do u <- DEQUEUE(Q)
for each v in Adj[u]
do if color[v] == white && color[u] == red
then color[v] <- blue
ENQUEUE(Q,v)
else if color[v] == white && color[u] == blue
then color[v] <- red
ENQUEUE(Q,v)
else if color[u] == color[v]
then break;
}
最终时间复杂度: O ( V + E ) O(V+E) O(V+E)