【问题标题】:Shortest path between two nodes with fixed number of nodes in path路径中节点数固定的两个节点之间的最短路径
【发布时间】:2021-12-18 01:28:30
【问题描述】:

我有一个包含大约 800 个节点的加权图,每个节点的连接数从 1 到大约 300 不等。我需要使用一些额外标准找到两个节点之间的最短(最低成本)路径:

  • 路径必须恰好包含五个节点。
  • 每个节点都有一个属性(在示例代码中称为position),它采用五个值之一;路径中的五个节点都必须具有该属性的唯一值。
  • 该算法需要允许指定 1-2 个必需节点,路径必须以任意顺序在某个点包含这些节点。
  • 算法的运行时间需要少于 10 秒,最好是时间越短,准确度损失越小。

我目前在 Python 中的解决方案是运行深度限制深度优先搜索,它递归地搜索每条可能的路径。为了使该算法在合理的时间内运行,我对在每个递归级别搜索的相邻节点的数量进行了限制。可以降低此数字以减少计算时间,但会以准确性为代价。目前这个算法太慢了,我最近的测试是 75 秒,邻居限制为 30。如果我再降低这个邻居限制,我的测试表明算法的准确性开始受到严重影响。我不知道如何在满足上述所有标准的同时解决这个问题。我的代码如下:

# The path must go from start -> end, be of length 5 and contain all nodes in middle
# Each node is represented as a tuple: (value, position)
def dfs(start, end, middle=[], path=Path(), best=Path([], math.inf)):
    # If this is the first level of recursion, initialise the path variable
    if len(path) == 0:
        path = Path([start])
    
    # If the max depth has been exceeded, check if the current node is the goal node
    if len(path) >= depth:
        # If it is, save the path
        # Check that all required nodes have been visited
        if len(path) == depth and start == end and path.cost < best.cost and all(x in path.path for x in middle):
            # Store the new best path
            best.path = path.path
            best.cost = path.cost
        return
    
    # Run DFS on all of the neighbors of the node that haven't been searched already
    # Use the weights of the neighbors as a heuristic; sort by lowest weight first
    neighbors = sorted([x for x in graph.get(*start).connected_nodes], key=lambda x: graph.weight(start, x))
    # Make sure that all neighbors haven't been visited yet and that their positions aren't already accounted for
    positions = [x[1] for x in path.path]
    # Only visit neighbouring nodes with unique positions and ids
    filtered = [x for x in neighbors if x not in path.path and x[1] not in positions]
    for neighbor in filtered[:neighbor_limit]:
        if neighbor not in path.path:
            dfs(neighbor, end, middle, Path(path.path + [neighbor], path.cost + graph.weight(start, neighbor)), best)
    
    return best

Path类:

class Path:
    def __init__(self, path=[], cost=0):
        self.path = path
        self.cost = cost
    
    def __len__(self):
        return len(self.path)

在改进此算法方面的任何帮助,甚至对解决问题的更好方法的建议将不胜感激,在此先感谢!

【问题讨论】:

    标签: python algorithm recursion graph-theory path-finding


    【解决方案1】:

    您应该遍历“位置”属性的所有可能排序,并为每一个排序使用 Dijkstra 算法或 BFS 来找到符合该排序的最短路径。

    因为你知道第一个和最后一个节点的位置,所以只有3个! = 6 种不同的中间节点排序,因此您只需运行 Dijkstra 算法 6 次。

    即使在 python 中,根据您提供的输入大小,这也不会超过几百毫秒的运行时间。

    【讨论】:

      猜你喜欢
      • 2016-03-04
      • 1970-01-01
      • 2023-01-15
      • 1970-01-01
      • 1970-01-01
      • 2017-04-18
      • 2015-06-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多