当前位置: 首页 > 知识库问答 >
问题:

Tarjan算法的Ruby版本中的Bug

慕高阳
2023-03-14

http://en.wikipedia.org/wiki/tarjan's_strongly_connected_components_algorithm

http://en.algoritmy.net/article/44220/tarjans-算法

我无法在我的Ruby版本的Tarjan算法中找出这个bug用于强连接组件。我得到了Kosaraju-Sharir算法,我的Tarjan算法在Ruby中适用于一些图。但它没有连接两个应该连接的组件--“10”和“11、12、9”

输入文件是这个有向图:http://algs4.cs.princeton.edu/42directed/tinydg.txt

expected: [["1"], ["0", "2", "3", "4", "5"], ["10", "11", "12", "9"], ["6", "8"], ["7"]]
got: [["1"], ["0", "2", "3", "4", "5"], ["10"], ["11", "12", "9"], ["6", "8"], ["7"]]

在这个尝试创建单个组件的最后一个循环中,它以“10”(堆栈上的最后一项)开始,但随后当前顶点(“父”)也是“10”!这使得循环切断“10”作为一个单独的组件。为什么堆栈上的最新项与父节点相同?我希望“10”只会出现在组件的末尾,在我们收集了[“12”,“11”,“9”...然后是“10”]之后。因为“10”首先出现,而不是最后出现,所以我们有这个问题。我怎么修好它?

  begin
    last_stack_item = stack.pop
    component << last_stack_item.name
  end while last_stack_item != parent # we're back at the root

我的Ruby代码:

    # Tarjan's algorithm to find all strongly connected components (SCCs)
    def scc_tarjan
      index = 0 # numbers nodes consecutively in the order discovered
      stack, scc, vertices = [], [], []

      # create new Struct, if not already defined
      if Struct::const_defined?("TarjanVertex")
        Struct.const_get("TarjanVertex")
      else
        Struct.new("TarjanVertex", :name, :index, :lowlink)
      end

      adj_lists.each do |v|
        # -1 means vertex is unvisited
        vertex = Struct::TarjanVertex.new(v.name, -1, -1)
        vertices << vertex  # array of all TarjanVertex objects in graph
      end
      vertices.each do |vertex|
        tarjan_dfs(vertex, scc, stack, index, vertices) if vertex.index == -1
      end
      # return nested array of all SCCs in graph
      scc
    end

  def tarjan_dfs(parent, scc, stack, index, vertices)
    # Set depth index for vertex to smallest unused index
    parent.index = index
    # lowlink is roughly the smallest index of any node known to be reachable from the vertex
    parent.lowlink = index
    index += 1
    stack << parent
    # loop through all vertices connected to parent
    adj_vertices(parent.name, adj_lists).each do |adj_vertex|
      # since adj_vertices returns array of strings,
      # must convert to TarjanVertex objects
      child = vertices.select {|v| v.name == adj_vertex}.first

      if child.index == -1  # if child vertex not yet visited
        tarjan_dfs(child, scc, stack, index, vertices) # recurse on child

        # change parent's lowlink to smaller lowlink of parent and child)
        parent.lowlink = [parent.lowlink, child.lowlink].min

      # vertex points to earlier (already visited) one in stack,
      # with lower index. thus it's the current SCC
      elsif stack.include?(child)
        parent.lowlink = [parent.lowlink, child.index].min
      end
    end

    # if a vertex's lowlink = its index here, this # cannot go any lower.
    # vertex MUST be root of the SCC.
    if parent.lowlink == parent.index
      component = []  # a single SCC

      # pop off entire SCC, one vertex at a time
      begin
        last_stack_item = stack.pop
        component << last_stack_item.name
      end while last_stack_item != parent # we're back at the root
      scc << component.sort # done with a single SCC
    end
  end

共有1个答案

钱修雅
2023-03-14

我解决了自己的问题!在用笔和纸检查了代码的每个循环之后,我发现它过早地进入了顶点4的底部组件循环。此时Parent.LowLink不应等于Parent.Index。我只需要修改一个词就能解决我的问题!

我在“elsif stack.include?(child)”循环中将“child.index”更改为“child.lowlink”!这正确地删除了4的下链接,以匹配顶点6的下链接。

从那时起,parent.lowlink!=parent.index,它不会过早地开始创建新组件。

有趣的是,我的解决方案不同于我在Tarjan算法上找到的所有伪代码和在线代码,它们都说“parent.lowlink=[parent.lowlink,child.index].min”

相反,我需要“parent.lowlink=[parent.lowlink,child.lowlink].min”

 类似资料:
  • Tarjan算法 问题: 用Tarjan算法求有向图(G)的强连通分支。 解法: Tarjan算法定义了概念“强连通分支的根节点”。对有向图(G)中的节点(i)(范围为([0, n))),设置一个(low_i)值,表示从节点(i)出发进行DFS可以到达的所有节点中最小的节点标号。若节点(i)满足(low_i = i),则该节点为强连通分支的根节点。 Tarjan算法分为(2)个步骤: ((1))对

  • 使用命令行工具,如何安装特定版本的gem?

  • 本文向大家介绍详解Ruby当中的算数运算,包括了详解Ruby当中的算数运算的使用技巧和注意事项,需要的朋友参考一下  Ruby支持一系列丰富的运算符的一个现代化的语言。大多数运算符实际上是方法调用。例如,a + b的被解释为a, +(b)变量引用的对象的方法被称为一个用b作为它的参数。 对于每个运算符 (+ - * / % ** & | ^ << >> && ||), 有相应的赋值运算符缩写形式

  • 涵盖了 Ruby 1.8 中新的和改进的特性以及标准库模块。它不仅是您学习Ruby语言及其丰富特性的一本优秀教程,也可以作为日常编程时类和模块的参考手册。

  • 本文向大家介绍快排算法(C C++版本)相关面试题,主要包含被问及快排算法(C C++版本)时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。  

  • 我是Ruby的新手,正在尝试我在Ruby中的前几个程序来理解这些概念。现在,在类方法概念中,在尝试基础知识时,我遇到了以下问题。 我有一个类方法“Servers.valid_requestor”。 这应该检查提供的用户名是否有效,它基于我正在使用的预定义用户名,如果是,它应该在main中执行某些代码。 现在这里的问题是,每当我尝试使用myI获取用户名nput.user_name它返回my_inpu