其他分享
首页 > 其他分享> > 我如何才能使最长节点的递归搜索更有效?

我如何才能使最长节点的递归搜索更有效?

作者:互联网

我正在尝试在有向无环图中找到最长的路径.此刻,我的代码似乎在运行时复杂度为O(n3).

该图的输入为{0:[1,2],1:[2,3],3:[4,5]}

#Input: dictionary: graph, int: start, list: path
#Output: List: the longest path in the graph (Recurrance)
# This is a modification of a depth first search
def find_longest_path(graph, start, path=[]):
    path = path + [start]
    paths = path
    for node in graph[start]:
        if node not in path:
            newpaths = find_longest_path(graph, node, path)
            #Only take the new path if its length is greater than the current path
            if(len(newpaths) > len(paths)):
                paths = newpaths

    return paths

它以如下形式返回节点列表: [0,1,3,5]

我怎样才能使它比O(n3)更有效?递归是解决此问题的正确方法,还是应该使用其他循环?

解决方法:

您可以在O(n e)中解决此问题(即,节点边的数量呈线性).

这个想法是您首先创建一个拓扑排序(我是Tarjan’s algorithm的粉丝)和一组反向边.如果您可以分解问题以利用现有解决方案,那么它总是有帮助的.

然后,您将拓扑排序向后移动,将其子节点的距离1推到每个父节点(如果有多个路径,则保持最大值).跟踪迄今看到的最大距离的节点.

完成对所有具有距离的节点的注释后,您可以从具有最大距离的节点开始,该距离将是最长的路径根,然后沿着图形走,选择比当前节点少一个数的子节点(因为它们位于关键路径上).

通常,在尝试找到最佳复杂度算法时,不要害怕一个接一个地运行多个阶段.从复杂性的角度来看,顺序运行的五个O(n)算法仍然是O(n),并且仍然优于O(n2)(尽管根据恒定的成本/因数和n的大小,实际运行时间可能会更差).

ETA:我刚刚注意到您有一个起始节点.这使得它成为进行深度优先搜索并保持到目前为止所看到的最长解决方案的简单情况,该解决方案无论如何都只是O(n e).递归很好,或者您可以保留已访问节点的列表/堆栈(每次回溯时寻找下一个孩子时都必须小心).

当您从深度优先搜索开始回溯时,您需要存储从该节点到叶子的最长路径,以便不重新处理任何子树.这也将用作已访问标志(即,除了在未进行路径测试的节点上进行递归操作之前,还要在subpath_cache测试中具有未进行节点的节点).除了存储子路径,您还可以存储长度,然后根据上述顺序值(关键路径)完成后重新构建路径.

ETA2:这是一个解决方案.

def find_longest_path_rec(graph, parent, cache):
    maxlen = 0
    for node in graph[parent]:
        if node in cache:
            pass
        elif node not in graph:
            cache[node] = 1
        else:
            cache[node] = find_longest_path_rec(graph, node, cache)

        maxlen = max(maxlen, cache[node])

    return maxlen + 1

def find_longest_path(graph, start):
    cache = {}
    maxlen = find_longest_path_rec(graph, start, cache)
    path = [start]
    for i in range(maxlen-1, 0, -1):
        for node in graph[path[-1]]:
            if cache[node] == i:
                path.append(node)
                break
        else:
            assert(0)
    return path

请注意,我已经删除了不在路径测试中的节点,因为我假设您实际上是按照要求提供了DAG.如果要进行检查,您应该真正提出一个错误而不是忽略它.还要注意,我已经在for的else子句中添加了断言,以证明我们必须始终在路径中找到有效的下一个(顺序)节点.

ETA3:最后的for循环有点令人困惑.我们正在考虑的是,在关键路径中,所有节点距离都必须是连续的.考虑节点0是距离4,节点1是距离3,节点2是距离1.如果我们的路径以[0,2,…]开始,则存在矛盾,因为节点0离叶的距离不是2而不是1.

标签:graph-algorithm,python
来源: https://codeday.me/bug/20191027/1947078.html