1、题目描述
题目来自算法导论第3版22章的第7题,题目描述如下
职业摔跤选手可以分为两种类型:“娃娃脸”(好人)型和“高跟鞋”(“坏人”)型。在任意一对职业摔跤选手之间都可能存在竞争关系。假定有nnn个职业摔跤手,并且有一个给出的竞争关系的rrr对摔跤手的链表。请给出一个时间复杂度为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) - 初始队列QQQ为空,随机选择一个顶点sss加入队列QQQ,sss的颜色着为红色。
时间:O(3)O(3)O(3) - 执行如下循环,如果队列QQQ不为空,从队列中弹出元素赋值给顶点uuu,遍历uuu的邻接链表(也可以是邻接矩阵),若链表非空,对于顶点uuu中邻接矩阵的元素vvv,如果vvv的颜色是白色且uuu的颜色是红色,那么将顶点vvv着成蓝色;若vvv的颜色是白色且uuu的颜色是蓝色,那么将顶点vvv着成红色;若顶点uuu的颜色和顶点vvv的颜色相同,那么直接break,表示该图不是二分图。在着色的过程,将顶点vvv加入到队列QQQ中。执行循环直到队列空为止。
时间: 队列出来元素O(V)O(V)O(V),邻接链表遍历O(2E)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)