如何找出一个强连通图的奇环 这个问题来自于《算法概论》的课后习题,我想了2天,最后想出一个可行的办法。 首先,对于环的问题,有两个常规的手段,一个是点染色,还有一个是利用边的分类。边的分类主要是肯定出环的存在性(或位置),而染色,则是区分奇环和偶环的关键,这也是我最后才想到的。 假定强连通有向图G的根是r,设r为红色,那么,咱们从r出发,每走一步,就把脚下的点染色为上一个点的相反的颜色(红变蓝,蓝变红),而且,曾经染色过的点能够重复染色。假设G有一个奇环,设这个奇环为v0,v1,v2.。。vn,v1.。。。而后,咱们会发现,存在一个从r出发的路径,使得v1被染色为红色,同时,也绝对存在一个从r出发的路径,使得v1被染色为蓝色。缘由是,v1处于一个奇环当中,咱们能够借助它来实现这个效果。反过来讲,假设存在一个从r出发的路径,使得某个点vk被染色为红色,同时也存在一个从r出发的路径,使得vk被染色为蓝色,那么,咱们能够判定,一定存在一个包含vk的奇环,这个结论也不难理解。因此,咱们就证实了如下结论: 强连通有向图G含有奇环 等价于 从r出发,可使得某个vk被染色为红色,而且也能够被染色为蓝色。 若是某个vk既能够是红色,又能够是蓝色,就意味着,它的前继结点也知足这个有趣的性质:既能够是红色也能够是蓝色。把这个性质一直往前推,就能够知道,r一定既能够是红色又能够是蓝色! 若是一条路径会使得某个点曾经被染色为红色和蓝色,那么这个路径咱们称为有趣路径。 由上面的讨论知道,有趣路径的存在性与奇环的存在性,是等价的。 而后,咱们从边的分类去分析。 假设T是G的dfs生成树。显然,T里的点是红蓝相间,梅花间竹的。 也就是说,若是没有那些前向边,反向边和横插边,不管咱们怎么走,都走不出一条有趣路径。而后,咱们逐条边地往T上面增长。 假如咱们增长的是前向边, (1)前向边的两个端点颜色相反,仍是没有有趣路径。 (2)不然,立刻就能够获得一条有趣路径。 假如咱们增长的是前向边, (1)前向边的两个端点颜色相反,仍是没有有趣路径。 (2)不然,立刻就能够获得一条有趣路径。 假如咱们增长的是反向边, (1)反向边的两个端点颜色相反,仍是没有有趣路径。 (2)不然,立刻就能够获得一条有趣路径。 假如咱们增长的是横叉边, (1)横叉边的两个端点颜色相反,仍是没有有趣路径。 (2)不然,立刻就能够获得一条有趣路径。 能够发现,只要碰到了两端点颜色相同的某条非树边,就立刻能够肯定一条有趣路径,从而立刻知道奇环的存在。 反过来讲,若是奇环存在,就必定能够找到两端点颜色相同的某条非树边,由于找不到的话,就确定不存在有趣路径,也就不存在奇环了。 因此,这个寻找强连通图G的奇环的算法就是: 对G进行dfs,同时染色,若是发现两端点颜色相同的某条非树边,就说明有奇环,否则,就说明没有奇环。 题外话: 图的问题,拆分强连通分支,边的分类,删除边,增长边(特别是往dfs和bfs树上面进行的增长边操做),删除点,增长点,还有染色,记录访问和离开时间,某个子图的首个被访问的点,这些都是很重要的思考方向。