二分图

注意:借鉴了很多其他博客的内容,还请见谅。

一. 二分图基础:

1. 什么是二分图:

        首先它的结构是一个G=(V,E)的无向图。它的特点是可以二分为两个互不相交的集合。这里的关键是互不相交是怎么定义的:如果有一条边e1,它的两个顶点分别为v1,v2,那么v1和v2就是相交的,就不能位于同一集合内。

例图1

        比如说上面的例图1中,1和3之间有一条边,所以1,3是相交的;2和3之间有一条边,所以2,3是相交的。1,3相交,所以1,3不能位于同一个集合,2,3也不能位于同一集合,但是1,2可以位于同一集合。所以可以将点集V划分为{1,2}和{3}这两个集合。可以将G=(V,E)中的点集V分成两个集合的图,就是二分图。


2. 二分图的性质:

        当且仅当无向图G的每一个环中,点的数量都是偶数时,G才是一个二分图。如果无环(考虑连通的情况),可以理解成每个环中,点的数量为0,也是偶数,所以也是一个二分图。这种情况可以画一画图,很容易把它画为二分图的常见形式。

例图2
例图3

        直观理解:例图2是二分图的常见表现形式,可以明显地看出,点集V可以划分为{1,2,5}和{3,4,6}两个集合,可以将这个图展开成例图3的形式。图中有3个环,{1,2,3,6},{2,4,5,6},{1,2,3,4,5,6}这三个集合可以分别构成一个环。这个时候其实可以有一个直觉,每一个环中,各有n/2的点来自二分图的二分集合。接下来进行验证。

        首先证明如果环中点的数量为奇数,那么一定不可能是二分图,请看下图:

例图4

        从1开始,假设图中有一部分是上面图中的环,并且假设这个图是一个二分图,二分集合分别为集合A,B。我们的目标是证明这种情况是不存在的。不妨设1属于集合A,因为1与2有边相连,所以2必然属于集合B;同理,因为3与2相连,所以3必然是属于集合A的,4属于集合B,5属于集合A,但是5与1有一条边直接相连,它们不能都属于集合A,因此这种情况必然是不成立的。说到这里,相信环中包含奇数个点时,必然不是二分图,这个证明已不再复杂。

        如果每个环中点的数量都为偶数,那么一定是二分图。关于这个证明,我暂时还没有了解到很严格的证明方法,因为证明不成立,只要找到合理的反例即可,但要是严谨的证明成立,这个可能需要十分完整的推理过程,这一点我暂时无法做到。不过可以参考例图4的想法,如果环中点的数量为偶数,那么必然集合内的点不会存在相交的冲突,因此只是一个环的时候,是可以做到的。如果两个环或者多个环共用了几个点,如果画图会看出,共用的情况,也不会带来任何相交的冲突。


3. 二分图的判定:

        直观想法:判断图中的每一个环,环中点的数量是奇数还是偶数,一旦发现奇数,结束过程,不是二分图,正常完成,则是二分图。

       要按照这个想法进行实现的话,要先去考虑,如果找到一个环。这一点并不难,无论是bfs还是dfs,都可以通过标记已访问过的点,来判断是否有环。但是这个思路有一个问题,比如说当前点cur,发现它的下一个点next已经被标记访问过了,这个时候可以判断有环,但是接下来需要判断这个环中点的数量是奇数还是偶数,这一点怎么实现?

        这个时候顺着这个思路往下走,可能会想,要做到这一点的话,我需要保存这个环上经过的所有点。好的,要实现这一点,通过dfs或者bfs可能还无法实现,还需要借鉴一下tarjan的思路,引入一个栈来存放节点。到此,这个问题已经很复杂了,根据我的一些浅薄的经验,这样来直接解决环的问题,往往会很麻烦。最重要的是,这通常不是比较好的思路。先接着上面的思路来分析,上面引入了tarjan来直接处理环,还没有解决所有问题。因为环还有可能面对两个小环组合成大环,或者大环套小环的问题,比如说下图所示:

例图5
例图6

        直接问题就是,如果出现环和环之间有共同点的情况该怎么办。这里提供一种思路,如果只是判断点的数量是奇数还是偶数,其实可以挑直接环来处理(这一点在tarjan中可以做到)。直接环就是说,比如说例图5,按照tarjan的一些模板算法,会把两个环合并成一个大环来处理,因为它们是连通的。但是直接环的话,就是发现了左边有一个环,就先处理左边这个环,然后继续处理,又发现了右边有了环,再处理右边的环。不必同时考虑大环和小环,只要考虑小环就可以了。

       这种做法的原因是,如果小环全都满足偶数个点,那么小环合并成的大环必然也满足。如果大环有奇数个点,那么必然存在小环有奇数个点。(比如例图6,大环9个点,但它内部有两个小环,一个4个点,另一个5个点)所以理论上这种方案是可以的。


        最后说一下比较好的,也应该是比较常规的算法,应该是dfs/bfs的染色思路。因为这里的目标只是判断环中点的数量是奇数还是偶数,那么可以提供两种颜色比如1和2,当前点是1的话,那么和它有直接边相连的点,遍历到时给它的颜色就是2。接下来,一定发现当前点的下一个节点已经访问过了,就看它的颜色,比如当前点是1,如果下一个节点已经访问过,并且也是1,那么说明这个环中有奇数个节点,反之,则为偶数个节点。

        最后一步,严谨的算法,需要考虑尽可能地详细。虽然这个算法看起来很不错了,但是我们仍然需要想一想,这个算法是不是可以处理到图中所有的环。如果这样dfs/bfs无法处理到图中所有的环,那很可能因为漏判,而导致不能用。

        对于例图5中的情况,这里dfs/bfs的时候,很容易可以分析出,两个环互相是不会有影响的。关键是例图6的情况,用 dfs/bfs是可以保证,假如上面的小环处理完之后,会返回处理下面的小环的(这里的解释有点混乱)。总之这里的含义就是,不会因为处理了一部分小环,而导致其他部分的小环没有处理到的,用dfs/bfs是可以保证,处理完一部分后,回溯到之前的节点,再处理其他所有可能的环。这里其实也可以理解为,dfs/bfs会把大环拆成小环来一个一个地处理,只不过没有像tarjan那样,保存了具体环的信息。dfs/bfs不保存环信息,直接利用颜色标记法来判断,无疑效率要高很多。

关于二分图的更多内容,会在之后做更多详细的总结。这是我的第一篇博客,希望可以有人喜欢,也希望之后自己积累更多,总结可以越来越清晰。

你可能感兴趣的:(二分图)