查找图中的所有循环,redux
我知道这个问题有很多答案。然而,我发现他们都没有真正说到点子上。
有些人认为循环(几乎)与强连接组件相同(s.查找有向图中的所有循环),因此可以使用为该目标设计的算法。
有些人认为可以通过 DFS 并检查后沿来找到循环(例如有关文件依赖性的 boost 图形文档)。
我现在想就是否可以通过 DFS 检测图中的所有循环并检查后沿提出一些建议?
http://www.me.utexas.edu/~bard/ IP/Handouts/cycles.pdf(在 SO 上找到)陈述了一种基于循环基础的方法。就我个人而言,我觉得它不是很直观,所以我正在寻找不同的解决方案。
编辑:我最初的意见显然是错误的。 S.下一个回答是“白痴”。
初步意见: 我的观点是,它确实可以这样工作,因为 DFS-VISIT(DFS 的伪代码)新进入尚未访问的每个节点。从这个意义上说,每个顶点都表现出一个循环的潜在开始。此外,由于 DFS 访问每条边一次,因此通向循环起点的每条边也被覆盖。因此,通过使用 DFS 和后沿检查,确实应该可以检测图中的所有周期。请注意,如果存在具有不同数量的参与者节点的循环(例如三角形、矩形等),则必须做额外的工作来区分每个循环的实际“形状”。
I know there are a quite some answers existing on this question. However, I found none of them really bringing it to the point.
Some argue that a cycle is (almost) the same as a strongly connected components (s. Finding all cycles in a directed graph) , so one could use algorithms designed for that goal.
Some argue that finding a cycle can be done via DFS and checking for back-edges (s. boost graph documentation on file dependencies).
I now would like to have some suggestions on whether all cycles in a graph can be detected via DFS and checking for back-edges?
http://www.me.utexas.edu/~bard/IP/Handouts/cycles.pdf (found here on S.O.) states one methode based on cycle bases. Me personally, I don't find it very intuitive so I'm looking for a different solution.
EDIT: My initial opinion was apparently wrong. S. next answer by "Moron".
Initial opinion:
My opinion is that it indeed could work that way as DFS-VISIT (s. pseudocode of DFS) freshly enters each node that was not yet visited. In that sense, each vertex exhibits a potential start of a cycle. Additionally, as DFS visits each edge once, each edge leading to the starting point of a cycle is also covered. Thus, by using DFS and back-edge checking it should indeed be possible to detect all cycles in a graph. Note that, if cycles with different numbers of participant nodes exist (e.g. triangles, rectangles etc.), additional work has to be done to discriminate the acutal "shape" of each cycle.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我已经彻底回答了这个问题,所以检查一下:
源删除排序总是返回最大循环吗?
答案的相关部分:
I have already answered this thoroughly, so check this:
Will a source-removal sort always return a maximal cycle?
The relevant part of the answer:
也许这可以以某种方式帮助你,我发现这个 描述有向图的彩色 dfs 的站点。因此,您可以考虑将我在这里介绍的 dfs 翻译更正为 php。
我添加的是创建森林的一部分和查找所有循环的另一部分。因此,请考虑将我的代码的这两部分确定为正确是不安全的。
具有图论知识的人也许能够进行测试。 dfs 部分没有注释,因为它已经在参考站点中进行了描述。我建议你举一个不止一棵树的例子,并在纸上画出森林(需要4种颜色),以便更好地理解。
这是代码:
这是输出:
编辑 1:
back_edge_exploit
方法可以被此版本取代:编辑 2:
我不得不说,我发现
back_edge_exploit
是不够的,它只能找到由树边和一个后边构成的循环。**** 编辑 3:****
虽然这个解决方案被发现是不完整的,但它有一些有用的信息,甚至它本身的不足也是一条信息,所以我认为保留它可能是有用的。但我编辑答案的主要原因是我找到了另一个解决方案,我将在下面介绍。
但在此之前,关于 dfs 方法的另一个注意事项是,通过遍历所有交叉、前向、树、后边缘的任何有效组合,可能会发生循环。因此,根据 dfs 信息找到实际周期并不简单(需要额外的代码),请考虑
这个例子:
只要涉及到新的解决方案,它就在 1970 年的旧论文中进行了描述,由James C. Tiernan(检查此链接)作为一种有效的算法查找有向图中的所有基本循环。还有一个无需转到的现代实现 在这里查看< /a>
我的基本循环算法(这就是名字)的实现是用 php 实现的,并且尽可能接近原始算法。我已经检查过了并且有效。这是关于有向图的,如果你声明你的图,以便有一个有向循环 v1->v2->v3 和另一个有向循环 v2->v3->v1 那么两个循环都会被发现,这是合乎逻辑的,因为它适用于有向图。
至于无向图,作者建议使用其他算法,这些算法比修改算法提供更好的解决方案,但是可以通过修改图定义并添加对长度为 2 的循环(被视为无向边)的额外检查来完成。特别是,三个节点的无向循环将在定义中定义两次,每个方向一次,如下所示:v1->v2->v3 和 v3->v2->v1。然后算法将找到它两次,每个方向一次,然后修改
EC3_Circuit_Confirmation
上的单行可以删除多余的一行。节点是按顺序定义的,可以更改常量
first
和邻接表,使第一个节点从零或一开始计数。这是 Tiernan 的 EC 算法的 php 代码:
Maybe this can help you somehow, I found this site where a colored dfs for directed graph is described. So you can consider correct the dfs translation to php I present here.
What I added is a part to create a forest and an other part to find all cycles. So please consider that it is not safe to take these two parts of my code as correct for sure.
One with knowledge on graph theory might be able to test for sure. There are no comments in the dfs part because it is described already in the reference site. I suggest that you take an example with more than one tree and draw the forest (need 4 colors) in a paper to better understand.
This is the code:
And this is the output:
EDIT 1 :
The
back_edge_exploit
method could be erplaced by this version:EDIT 2:
I have to say that I have found that
back_edge_exploit
is insufficient it will only find cycles that are made with tree edges and one back edge.**** Edit 3: ****
Although this solutions is found to be incomplete, it has some useful information, even the insufficiency it self is a piece of information, so I think it might be useful to keep it. But the main reason I have edited my answer is that I have found an other solution which I am going to present below.
But before that an other notice could be made about the dfs aproach, there are cycles that could occur by walking any valid combination all cross,forward,tree,back edge. So finding the actual cycles relying on the dfs information is not trivial (requires extra code), consider
this example:
As long as the new solution is concerned it is described in an old paper of 1970, by James C. Tiernan (Check this link) as an efficient algorithm for finding all elementary cycles in a directed graph. Also there is a modern implementation of this without goto See it here
My implementation of Elementary Cycle Algorithm (that's the name) is in php and is as close to the original as possible . I have already checked it and it works. It is about directed graphs, if you declare you graph so that there is a directed cycle v1->v2->v3 and an other one v2->v3->v1 then both cycles will be found which is logical since it works on directed graphs.
As for undirected graphs the author suggests other algorithms which make a better solution than modifying the algorithms, however it can be done by modifying the graph definition and by adding an extra check for cycles of length 2 which are considered as undirected edges. In particular an undirected cycle of three nodes would be defined twice in the definition, once per orientation, like this: v1->v2->v3 and v3->v2->v1. Then the algorithm will find it twice, once per orientation, then a modification of a single line on
EC3_Circuit_Confirmation
can cut the extra one.The nodes are defined sequentially, one can change the constant
first
and the adjacency list to make the first node count from zero or one.This is the php code for the EC Algorithm of Tiernan :
我的建议是使用 Tarjan 算法来查找强连通分量集,并使用 Hierholzer 算法来查找强连通分量中的所有循环。
以下是带有测试用例的 Java 实现的链接:
http://stones333.blogspot.com/2013 /12/find-cycles-in-directed-graph-dag.html
My suggestion is to use Tarjan's algorithm to find set of strongly connected components, and Hierholzer's algorithm to find all cycles in the strongly connected component.
Here is the link for the Java implementation with a test case:
http://stones333.blogspot.com/2013/12/find-cycles-in-directed-graph-dag.html
如果遍历算法仅访问每条边一次,则它无法找到所有循环。一条边可以是多个周期的一部分。
顺便说一句,什么是后缘?
另外,也许你应该重新表述/格式化你的问题。这是非常难读的。
If a traversal algorithm visits each edge only once, then it cannot find all cycles. An edge could be part of multiple cycles.
btw, what is a back-edge?
Also, perhaps you should rephrase/format your question. It is very hard to read.