我有一个包含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中继续它?
答案 0 :(得分:3)
euler路径一次访问每个边缘正好,所以我猜你不需要它。我能提供的是这样的:
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]]
此代码的作用是什么?
此算法不是采用可在我们的路径中使用的第一个边缘,而是 all 可以在路径中使用的边缘。
对于每个这样的边缘,它构建了一条新路径:
available
数组这将构建所有可能的路径的列表。从这个方法返回最长(最大长度)。
我标记为# hack
的三行是因为当first_chain
为nil
时,算法会找到以任何非反转边开头的最长路径。为了支持反转边缘,我运行它两次 - 第二次反转所有边缘。
这是不是已知算法的实现,而是一个简单的暴力实现,它可能不是最有效,最简单或最美观的,但它应该让您朝着正确的方向前进。您可以在ruby here
中找到有关使用图表的更多信息答案 1 :(得分:0)
虽然可能有更好的方法
,但这样的事情可能对你有用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