问题描述:给定一个无向图G=<V,E>,如何能够在O(V+E)时间内判断这个图是否是一个二分图(或者称为2着色)
c是从v到s和从u道s的交叉点,c当然可以和s相同,如果当前节点v相邻的节点u已经被标记为灰色(即正在栈中、或递归调用还没返回),那么这个图就是存在环路的,如何判断当前环路的边是否是奇数呢,不是一般性,假设d2>d3,那么我们只需要判断d2-d3+1是否为奇数,如果是奇数,则return false,证明当前图不是二分,如果是偶数则继续遍历,直到所有点均已遍历完毕,则返回true。
方法2:我们还可以利用类似减枝的方法来判断图中的回路是否为偶数,基本思想是这样的,如果一个无向图中存在环路,那么在这个环路中每个节点的度数>=2,。
分析:如果这个无向图没有回路,那么它一定是可以二分的,我们直接就可以利用BFS来为二分图着色(根据当前节点的颜色,对其所有相邻节点涂另一个颜色)。
如果这个无向图有回路,如果回路的边数是偶偶数,那么它还是二分的,如果是奇数,那么它就不是二分的。如何判断回路的边数是奇数还是偶数呢?
方法1:利用DFS记录初始节点到每个节点的距离d[],初始节点为s,假设当前访问节点为v,如图:
d2-d3正是从v到c和从u到c距离的差值,环c->....->v->u->...->c的变长可以表示为N=2*d3+d2-d3+1,所以N的奇偶性完全由d2-d3+1决定。当然在DFS遍历的时候也可能出现如下情形:
当前访问的节点v,与它相邻的节点u已经是灰色,那么按照刚才的分析,color[u]="Gray",但中不一定构成回路,但我们的判断d2-d1+1依然正确,因为这种情况下d2-d1+1=2,一定是偶数
时间代价O(V+E),空间O(1)(不考虑本身图所占用的结构开销)
1,首先,我们需要统计每个节点的度数,记录在degree[n]中 O(V+E)
2,删除所有度数<=1的节点(删除操作就是将该节点对应的边删除,并将对应的顶点的度数-1),然后将所有更新后的顶点度数为1的点加入队列当中。O(V)
3,然后对队列中的每个元素重复步骤1,最后如果还有没有被删除的节点(即还存在度数>=2的节点),证明图中存在回路。如果全部都已删除则图中不存在回路,即图是二分的
4,(上面的过程看做预处理过程)如果存在回路,接下来,对剩下的每一个节点,统计从这个节点开始的所有回路(即用DFS从这一点开始,又回到这一点的所有回路),并记录其路径的长度,并标记被访问的状态,如果存在偶数边则return false。
5,如果存在还没有被访问的点(另一个连通分支的回路),继续步骤4,知道所有节点都被访问完毕,return true.
方法2的复杂度要高一些,应该有一些可以优化的地方。