【问题标题】:Generating path over the graph Ruby在图 Ruby 上生成路径
【发布时间】:2026-01-31 14:45:01
【问题描述】:

我有一个包含 12 个节点的无向​​图,我生成了一个这样的数组:

arr = [[3, 12], [8, 12], [0, 3], [0, 5], [0, 10], [7, 9], [5, 5], [4, 9], [5, 12], [0, 1]] 

表示图的边。

我想找到通过图形的最长可能路径,例如每条边最多使用一次。对于给定的示例,它将类似于:

arr = [[1, 0], [0, 5], [5, 5], [5, 12], [12, 3], [3, 0], [0, 10]]

我通过搜索欧拉路径在许多资源上看到了这个问题的解决方案,但用其他编程语言编写​​。我将如何在 Ruby 中继续使用它?

【问题讨论】:

    标签: ruby arrays algorithm sorting graph-algorithm


    【解决方案1】:

    欧拉路径访问每个边缘恰好一次,所以我猜你不需要那个。我能提供的是这样的:

    def find_path(arr, first_chain = nil, path = [], available = arr.dup)
      edge_idx = available.index do |first, _| 
        first_chain.nil? || first == first_chain
      end
      unless edge_idx
        return path
      end
      edge = available.delete_at(edge_idx)
      path << edge
      find_path(arr, edge.last, path, available)
    end
    
    arr = [[0, 5], [3, 0], [5, 5], [1, 0], [0, 10], [5, 12], [12, 3]]
    
    find_path arr
    # => [[0, 5], [5, 5], [5, 12], [12, 3], [3, 0], [0, 10]] 
    
    find_path arr, 1
    # => [[1, 0], [0, 5], [5, 5], [5, 12], [12, 3], [3, 0], [0, 10]] 
    

    这个算法找到从第一个元素开始的一些路径,或者任何其他给定的整数。 保证它使用所有元素,或者它甚至可能是最长的,但它是一条路径......


    对于无向图,您需要考虑到边可能会反转:

    def find_path(arr, first_chain = nil, path = [], available = arr.dup)
      edge_idx = available.index do |edge| 
        first_chain.nil? || edge.include?(first_chain)
      end
      unless edge_idx
        return path
      end
      edge = available.delete_at(edge_idx)
      edge = edge.reverse if first_chain && edge.first != first_chain
      path << edge
      find_path(arr, edge.last, path, available)
    end
    
    find_path arr
    # => [[0, 5], [5, 5], [5, 12], [12, 3], [3, 0], [0, 1]] 
    
    find_path arr, 1
    # => [[1, 0], [0, 5], [5, 5], [5, 12], [12, 3], [3, 0], [0, 10]] 
    

    要找到最长的路径,你需要构建所有条可能的路径,并选择最长的:

    def find_longest_path(arr, first_chain = nil, available = arr.dup)
      paths = available.each_index.select do |edge_idx| 
        first_chain.nil? || available[edge_idx].include?(first_chain)
      end.map do |edge_idx|
        edge = available[edge_idx]
        edge = edge.reverse if first_chain && edge.first != first_chain
        [edge, *find_longest_path(arr, edge.last, 
                             available[0...edge_idx] + available[edge_idx+1..-1])]
      end
      # a hack to find longest in all reverse paths
      if first_chain.nil? && arr == available
        paths << find_longest_path(arr, nil, arr.map(&:reverse))
      end
      paths.max_by { |path| path.length }
    end
    
    arr = [[3, 12], [8, 12], [0, 3], [0, 5], [0, 10], [7, 9], [5, 5], [4, 9], [5, 12], [0, 1]]
    
    find_longest_path arr
    # => [[10, 0], [0, 3], [3, 12], [12, 5], [5, 5], [5, 0], [0, 1]] 
    
    find_longest_path arr, 1
    # => [[1, 0], [0, 3], [3, 12], [12, 5], [5, 5], [5, 0], [0, 10]]
    

    这段代码有什么作用?
    该算法不采用可在我们的路径中使用的 first 边,而是采用 所有 可在我们的路径中使用的边。

    对于每个这样的边缘,它会构建一个新路径:

    1. 从选定的边开始
    2. available 数组中移除边
    3. 从边缘的出顶点(递归)开始,继续最长路径

    这将构建所有可能路径的列表。从此方法返回最长的(最大长度)。

    我标记为# hack 的三行是因为当first_chainnil 时,算法会找到以任何非反向边 开头的最长路径。为了支持反转的边缘,我运行了两次 - 第二次所有边缘都反转了。

    不是一个已知算法的实现,而是一个简单的蛮力实现,它可能不是最有效、最简单或最美观的,但它应该让你朝着正确的方向前进。您可能会在 ruby​​ here 中找到有关使用 Graphs 的更多信息

    【讨论】:

    • 肯定是不错的方法,但根据他的初始 arr 它返回 [[3,12]] 作为完整路径。我认为问题在于数组生成,因为您的方法适用于满足算法要求的数组。
    • @engineersmnky - 要求不明确,也许他允许改变边缘的方向。如果我愿意的话,我可能会在明天添加该功能......
    • 实际上,您似乎已经根据他的duplicate 回答了这个问题,他正在寻找最长的路径。你的方法做得很好。
    • @Uri Agassi 我学习了 Ruby,但仍然不太精通语言的语法和算法。您能否展示为数组的所有元素而不是第一个元素寻找欧拉路径的解决方案?我知道我需要在循环中添加 edge_idh?
    • @Ruby - 我所做的不是欧拉路径实现,而是直接的蛮力路径查找。你似乎已经完全编辑了这个问题,这很不幸,因为这不是我打算回答的问题。我可以添加找到 longest 路径的代码版本,但不是根据任何已知算法 (AFAIK)
    【解决方案2】:

    尽管可能有更好的方法,但这样的方法可能对你有用

    def generate_array
      a = []
      b2 = nil
      10.times do 
        b1,b2 = [b2 || rand(12),rand(12)]
        a << [b1,b2]
      end
      a
    end
    generate_array
    #=> [[0, 4], [4, 4], [4, 11], [11, 4], [4, 8], [8, 11], [11, 4], [4, 2], [2, 6], [6, 0]]
    

    还只是基于您给定输出的注释rand(12) 永远不会返回12,因为上限是使用 0 索引设置的,因此要返回的最大数字是 11

    【讨论】:

    • 显然你误解了这个问题,意思是你需要在图上生成一条路径,即数组中已经生成了一条链。
    • @Ruby 你的问题在这一点上还不清楚,路径生成包括不在原始数组中的元素。似乎有人做了你正在寻找的东西here