簡體   English   中英

給出有向圖中的循環示例

[英]Giving an example of a cycle in a directed graph

我想要一個算法,如果有的話,在有向圖中給出一個循環的實例。 誰能告訴我一個方向? 在偽代碼中,或者最好是在Ruby中?

我之前問了一個類似的問題 ,並按照那里的建議,我在Ruby中實現了Kahn的算法,它檢測圖形是否有一個循環,但我不僅要求它是否有一個循環,而且還要一個這樣的循環的可能實例。

example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 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, 3], [3, 6], [6, 2]]

如果我在檢查結束時在上面的代碼中輸出變量graph ,它將給出:

#=> [[2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]

其中包括我想要的循環,但它還包括與循環無關的額外邊。

我在math stackexchange網站上問了同樣的問題,並得到了答案。 事實證明,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], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
DirectedGraph.strongly_connected_components(example_graph)
#=> [[4], [5], [2, 3, 6], [1]]

通過選擇那些長於1的組件,我得到了循環:

DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
#=> [[2, 3, 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, 3], [3, 6], [6, 2]]]

深度優先搜索,跟蹤訪問的頂點,父級將為您提供循環。 如果您看到先前訪問過的頂點的邊緣,那么您已經檢測到父節點,您自己和該頂點之間的循環。 您可能遇到的一個小問題是,如果它是一個長度> 3的循環,您將只能告訴所涉及的三個頂點,並且必須對循環中的其余頂點進行一些調查。

對於調查,您可以從父項開始向上搜索“向上”,並查找訪問的頂點,您應該能夠通過這樣做找到整個循環。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM