欧拉路径访问每个边缘恰好一次,所以我猜你不需要那个。我能提供的是这样的:
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 边,而是采用 所有 可在我们的路径中使用的边。
对于每个这样的边缘,它会构建一个新路径:
- 从选定的边开始
- 从
available 数组中移除边
- 从边缘的出顶点(递归)开始,继续最长路径
这将构建所有可能路径的列表。从此方法返回最长的(最大长度)。
我标记为# hack 的三行是因为当first_chain 是nil 时,算法会找到以任何非反向边 开头的最长路径。为了支持反转的边缘,我运行了两次 - 第二次所有边缘都反转了。
这不是一个已知算法的实现,而是一个简单的蛮力实现,它可能不是最有效、最简单或最美观的,但它应该让你朝着正确的方向前进。您可能会在 ruby here 中找到有关使用 Graphs 的更多信息