I want an algorithm that gives one instance of a cycle in a directed graph if there is any. Can anyone show me a direction? In pseudo-code, or preferably, in Ruby?
I previously asked a similar question, and following the suggestions there, I implemented Kahn's algorithm in Ruby that detects if a graph has a cycle, but I want not only whether it has a cycle, but also one possible instance of such cycle.
example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
Kahn's algorithm
def cyclic? graph
## The set of edges that have not been examined
graph = graph.dup
n, m = graph.transpose
## The set of nodes that are the supremum in the graph
sup = (n - m).uniq
while sup_old = sup.pop do
sup_old = graph.select{|n, _| n == sup_old}
graph -= sup_old
sup_old.each {|_, ssup| sup.push(ssup) unless graph.any?{|_, n| n == ssup}}
end
!graph.empty?
end
The above algorithm tells whether a graph has a cycle:
cyclic?(example_graph) #=> true
but I want not only that but an example of a cycle like this:
#=> [[2, 3], [3, 6], [6, 2]]
If I were to output the variable graph
in the above code at the end of examination, it will give:
#=> [[2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
which includes the cycle I want, but it also includes extra edges that are irrelevant to the cycle.
I asked the same question in the math stackexchange site, and got an answer. It turned out that Tarjan's algorithm is good for solving this problem. I implemented it in Ruby as follows:
So if I apply it to the example above, I get a list of strongly connected components of the graph:
By selecting those components that are longer than one, I get the cycles:
And further if I select from the graph the edges whose both vertices are included in the components, I get the crucial edges that constitute the cycles:
Depth first search, where you keep track of the visited vertices and the parent will give you the cycle. If you see an edge to a previously visited vertex then you have detected a cycle between your parent, yourself, and that vertex. A slight problem you may encounter is, if it is a cycle of length > 3, you'll only be able to tell the three vertices involved and will have to do some investigation into finding the rest of the vertices in the cycle.
For the investigation, you can start a breadth first search 'up' the tree starting from the parent and looking for the visited vertex, you should be able to find the whole cycle by doing that.