微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ruby – 在有向图中给出一个循环的例子

我想要一个算法,如果有的话,在有向图中给出一个循环的实例.谁能告诉我一个方向?在伪代码中,或者最好是在 Ruby中?

我之前问过a similar question,并按照那里的建议,我在Ruby中实现了Kahn的算法,它检测图表是否有一个循环,但我不仅要求它是否有一个循环,而且还要一个这样的循环的可能实例.

example_graph = [[1,2],[2,3],[3,4],5],6],[6,2]]

卡恩的算法

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

上面的算法告诉图表是否有一个循环:

cyclic?(example_graph) #=> true

但我不仅要这样,而且要像这样的循环示例:

#=> [[2,2]]

如果我在检查结束时在上面的代码输出变量图,它将给出:

#=> [[2,2]]

其中包括我想要的循环,但它还包括与循环无关的额外边.

解决方法

我在 the math stackexchange site问了同样的问题,得到了答案.事实证明,Tarjan的算法有助于解决这个问题.我在Ruby中实现它如下:

module DirectedGraph; module_function
    ## Tarjan's algorithm
    def strongly_connected_components graph
        @index,@stack,@indice,@lowlink,@scc = 0,[],{},[]
        @graph = graph
        @graph.flatten(1).uniq.each{|v| strong_connect(v) unless @indice[v]}
        @scc
    end
    def strong_connect v
        @indice[v] = @index
        @lowlink[v] = @index
        @index += 1
        @stack.push(v)
        @graph.each do |vv,w|
            next unless vv == v
            if !@indice[w]
                strong_connect(w)
                @lowlink[v] = [@lowlink[v],@lowlink[w]].min
            elsif @stack.include?(w)
                @lowlink[v] = [@lowlink[v],@indice[w]].min
            end
        end
        if @lowlink[v] == @indice[v]
            i = @stack.index(v)
            @scc.push(@stack[i..-1])
            @stack = @stack[0...i]
        end
    end
end

因此,如果我将其应用于上面的示例,我会得到图表中强连接组件的列表:

example_graph = [[1,2]]
DirectedGraph.strongly_connected_components(example_graph)
#=> [[4],[5],3,[1]]

通过选择那些长于1的组件,我得到了循环:

DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
#=> [[2,6]]

而且如果我从图中选择两个顶点都包含在组件中的边,我得到构成循环的关键边:

DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
.map{|a| example_graph.select{|v,w| a.include?(v) and a.include?(w)}}
#=> [[[2,2]]]

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐