如何从有向图中找到(迭代)有向图中的所有周期?
例如,我想要这样的东西:
A->B->A A->B->C->A
但不是:B-> C-> B.
我在搜索中发现了这个页面,因为循环与强连接组件不同,我继续搜索,最后,我找到了一个有效的算法,列出了有向图的所有(基本)周期.它来自Donald B. Johnson,论文可以在以下链接中找到:
http://www.cs.tufts.edu/comp/150GA/homeworks/hw1/Johnson%2075.PDF
可以在以下位置找到java实现:
http://normalisiert.de/code/java/elementaryCycles.zip
一个数学约翰逊的算法演示可以发现这里实现,可以从右边(下载"下载作者码").
注意:实际上,这个问题有很多算法.其中一些列在本文中:
http://dx.doi.org/10.1137/0205007
根据文章,约翰逊的算法是最快的算法.
使用回溯的深度优先搜索应该在这里工作.保留一个布尔值数组,以跟踪您之前是否访问过某个节点.如果你的新节点用完了(没有点击你已经存在的节点),那么只需回溯并尝试不同的分支.
如果您有一个邻接列表来表示图形,则DFS很容易实现.例如adj [A] = {B,C}表示B和C是A的子节点.
例如,下面的伪代码."start"是您从哪个节点开始的.
dfs(adj,node,visited): if (visited[node]): if (node == start): "found a path" return; visited[node]=YES; for child in adj[node]: dfs(adj,child,visited) visited[node]=NO;
使用start节点调用上述函数:
visited = {} dfs(adj,start,visited)
首先 - 你真的不想尝试找到字面上的所有周期,因为如果有1那么就有无数个.例如ABA,ABABA等.或者可以将2个周期连接到8个周期等等......有意义的方法是寻找所有所谓的简单周期 - 那些不会跨越自己的周期在开始/结束点.然后,如果您希望您可以生成简单循环的组合.
在有向图中查找所有简单循环的基线算法之一是:在图中对所有简单路径(那些不自交的路径)进行深度优先遍历.每当当前节点在堆栈上具有后继节点时,就会发现一个简单的循环.它由堆栈中的元素组成,从标识的后继开始到堆栈顶部结束.所有简单路径的深度优先遍历类似于深度优先搜索,但是您不会将当前在堆栈上的访问节点标记/记录为停止点.
上面的强力算法非常低效,并且除此之外还生成多个循环副本.然而,它是多种实用算法的起点,它们应用各种增强功能以提高性能并避免循环重复.前一段时间我很惊讶地发现这些算法在教科书和网络上都不容易获得.所以我做了一些研究,并在开源Java库中的无向图中为循环实现了4个这样的算法和1个算法:http://code.google.com/p/niographs/.
顺便说一句,因为我提到了无向图:那些算法不同.构建生成树,然后不是树的一部分的每个边与树中的一些边形成一个简单的循环.发现这种循环形成了一个所谓的循环基础.然后可以通过组合2个或更多个不同的碱基循环来找到所有简单循环.有关详细信息,请参阅:http://dspace.mit.edu/bitstream/handle/1721.1/68106/FTL_R_1982_07.pdf.
我发现解决这个问题的最简单的选择是使用被调用的python lib networkx
.
它实现了在这个问题的最佳答案中提到的约翰逊算法,但它的执行非常简单.
简而言之,您需要以下内容:
import networkx as nx import matplotlib.pyplot as plt # Create Directed Graph G=nx.DiGraph() # Add a list of nodes: G.add_nodes_from(["a","b","c","d","e"]) # Add a list of edges: G.add_edges_from([("a","b"),("b","c"), ("c","a"), ("b","d"), ("d","e"), ("e","a")]) #Return a list of cycles described as a list o nodes list(nx.simple_cycles(G))
答案: [['a','b','d','e'],['a','b','c']]
澄清:
强连接组件将查找其中至少有一个循环的所有子图,而不是图中所有可能的循环.例如,如果你采用所有强连接组件并将它们中的每一个折叠/分组/合并为一个节点(即每个组件的一个节点),你将获得一个没有循环的树(实际上是一个DAG).每个组件(基本上是一个至少有一个循环的子图)可以在内部包含更多可能的循环,因此SCC将找不到所有可能的循环,它将找到至少有一个循环的所有可能组,如果您组他们,然后图表将没有周期.
如同其他人提到的那样,在图中找到所有简单周期,约翰逊的算法是一个候选者.