You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

71 lines
1.2 KiB
Ruby

require 'set'
# Finding a directed cycle in a directed graph.
# The graph is represented as an adjacency list of Integers,
# see examples in test/directed_cycle_test.rb
class DirectedCycle
class Digraph
attr_accessor :adj, :size
def initialize(size)
@size = size
@adj = Array.new(size) { Set.new }
end
def add_edge(v, w)
@adj[v].add(w)
end
end
def initialize(graph)
@graph = graph
@cycle = []
@visited = Array.new(graph.size, false)
@on_stack = Array.new(graph.size, false)
@edge_to = Array.new(graph.size, nil)
graph.size.times do |v|
dfs(v) unless @visited[v]
end
end
def has_cycle?
@cycle.any?
end
def cycle
@cycle
end
private
def dfs(v)
@visited[v] = true
@on_stack[v] = true
@graph.adj[v].each do |w|
return if has_cycle?
if @visited[w]
track_cycle(v, w) if @on_stack[w]
else
@edge_to[w] = v
dfs(w)
end
end
@on_stack[v] = false
end
def track_cycle(from, to)
v = from
while v != to
@cycle.push(v)
v = @edge_to[v]
end
@cycle.push(to)
@cycle.push(from)
@cycle.reverse!
end
end