使用BFS在有向图中查找周期?

时间:2013-09-26 12:45:29

标签: java graph cycle

我考虑过标记我访问过的所有节点。当我发现一些标志设置的节点是循环时。但这不会起作用,因为一个节点可以有多个父节点和多个子节点。如何才能找到循环?

PS:我知道寻找周期更适合DFS,但我需要通过BFS来做。

2 个答案:

答案 0 :(得分:0)

找出直接图是否包含循环与确定图是否具有拓扑排序/顺序是相同的问题。也就是说,找出图的所有顶点是否可以线性方式排列,其中任何一个顶点的所有出站边总是指向其右端的另一个顶点。

概念是这样的;具有拓扑排序的图(也称为有向无环图(DAG))将始终至少具有一个没有任何入边界的顶点。您可以很容易地通过矛盾证明这一说法:如果每个顶点都有入边界,那么在图形中向后走将最终导致一次走过两次顶点,这意味着它具有一个循环,而不是DAG。

从DAG中删除顶点及其出站边缘将永远不会导致创建新循环。在拓扑顺序的线性视觉表示中,最左边的顶点没有入边界。如果一个人按拓扑顺序一一移除最左边的顶点及其边缘,则它们将始终移除不具有边界边缘的顶点,因为它们要么开始时没有任何顶点,要么其边界边缘被其他对象去除顶点被删除。在将顶点自身删除之前,只有那些没有任何入边界和出边界的顶点会保留。

如果依次删除每个没有入边界边缘的顶点并不能清除图形中的每个顶点,则意味着图中存在一个循环,并且它不是DAG。


按照这个想法,可以与FIFO数据结构一起使用以支持BFS的算法将是首先确定所有顶点上入站边的数量。您可以通过在开始时执行BFS来实现此目的,对于发现的每个出站边缘,请在其主要邻接列表节点中递增该对应邻居的入站边缘计数器。

在算法的本质上,您需要搜索顶点并将当前没有入边界的顶点添加到队列中。添加所有当前可用的对象后,从队列的最前面开始检查顶点。通过遍历其邻居并将每个入站边缘计数减1,以及检查新计数是否达到零,将其从图中删除。如果确实如此,则将该顶点添加到队列中。完成递减后,移至队列中的下一个顶点。对队列上的所有顶点继续相同的过程。这个过程看起来像是来自每个顶点的多个BFS,这些顶点没有入边界。

最后,如果删除的顶点数量与顶点总数相同,则该图为DAG,不包含循环。如果不是,则表示一个或多个循环中有剩余的顶点。

尽管这个问题已经很老了,但祝您好运!

答案 1 :(得分:0)

以上答案是正确的,但我认为它不是BFS或至少不是直观的BFS。它主要取决于检查每个节点的输出边缘并删除没有输入边缘的连接到节点的边缘。我的答案可能是针对此问题的更直观的BFS实现。

让我们思考一下什么是周期?

一个节点可以找到一条到达自己的路径,然后有一个循环。

那为什么DFS可以解决搜索周期任务而BFS无法解决?

要在有向图中找到循环,我们首先想出DFS:如果DFS树中有一个后沿,则图中将有一个循环。建立DFS树时,我们可以记录每个节点的开始计数器和结束计数器,以便我们可以检查指向节点是否是当前节点的祖先。一旦找到后边缘(指向节点未完成但在当前节点之前开始),这意味着该节点可以找到返回其祖先之一的方式。虽然BFS可以用来全面探索邻居,但却无法保存祖先。因此,如果通过图表保存祖先,也许我们可以使BFS解决此问题:

在BFS期间,当每个节点探索其邻居(或子节点)时,会将累积的祖先信息发送到其邻居。当节点发现从其父代传来的祖先之一是他本人时,则图中将出现一个循环。 这是显示该算法步骤的图片:enter image description here

步骤1,A探索了他的邻居:B,C,D,E,并将祖先信息{A}发送给他们。

步骤2,B探索了他的邻居E,并向其发送祖先信息{A,B}。

步骤3,C探索邻居D,F,并将祖先信息{A,C}发送给他们。

步骤4,D没有发现邻居。

步骤5,F探索了他的邻居D,G,并将祖先信息{A,C,F}发送给他们。

步骤6,G探索了他的邻居C,并向其发送祖先信息{A,C,F,G}。然后C会发现他的祖先是他本人,然后会有一个循环。

然后,该算法的运行时间如何?传统BFS的运行时间为Theta(V + E),但在此算法中,祖先信息的传递和并集将占用总共E步,而在每一步中,信息数组的大小都比C * V小1。因此,总运行时间为O(EV),Omega(V + E)。

相关问题