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: