【问题标题】:Trouble with list surviving through recursion in python; finding all possible routes on a graph通过 python 中的递归存在的列表存在问题;在图上查找所有可能的路线
【发布时间】:2016-12-04 04:04:55
【问题描述】:

我正在编写一个 python 程序,它采用完全连接的图(您可以从任何其他节点转到图上的任何节点)并在该图上找到所有可能的路线,这些路线短于给定的最大距离。

这是我迄今为止编写的代码:

def find_all_routes (cur_node, graph, willing_to_travel, visited, routesdict):
    """ Finds all routes possible within a certain distance.
    inputs
        cur_node: a dictionary with n entries, each of which is the distance to the nth
            dictionary in graph.
        graph: a list of n dictionaries, each of which contains n entries, each of which
            is the distance to the nth item in the list.
        willing_to_travel: the maximum distance we are willing to travel.
        visited: initialized as an empty list, will be populated nodes we've been to.
        all_routes: initialized as an empty list.
    Affects:
        all_routes is populated with every route permutation that can be traveled in under willing_to_travel distance.
    """
    #Add our current location to the visited list.
    for i in cur_node:
        if cur_node[i] == 0:
            visited.append(graph[i])

    # Add the current route to the dictionary.
    entry_no = len(routesdict)
    routesdict[entry_no] = visited
    print ("routesdict", routesdict)            # Just for diagnostic purposes.

    # Recursion with other nodes we can reach as the new start node.
    for i in cur_node:                               # For every place in the dictionary
        if graph[i] not in visited:                  # if we have not been there
            if cur_node[i] <= willing_to_travel:     # And if we can afford to go there
                find_all_routes(graph[i], graph, willing_to_travel - cur_node[i], visited, routesdict)

    return routesdict

def main():

    graph = [
        {0: 0.00, 1: 0.12, 2: 0.10},
        {0: 0.12, 1: 0.00, 2: 0.22},
        {0: 0.10, 1: 0.22, 2: 0.00}]

    max_distance = 10.0
    been_to = []
    routesdict = dict()

    routes = find_all_routes (graph[0], graph, max_distance, been_to, routesdict)

print ("Final output: ", routes)

if __name__ == "__main__":
    main()

由此产生的输出是:

routesdict:    {0: [{0: 0.0, 1: 0.12, 2: 0.1}]}
routesdict:    {0: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}], 1: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}]}
routesdict:    {0: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}, {0: 0.1, 1: 0.22, 2: 0.0}], 1: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}, {0: 0.1, 1: 0.22, 2: 0.0}], 2: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}, {0: 0.1, 1: 0.22 , 2: 0.0}]}
Final output:  {0: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}, {0: 0.1, 1: 0.22, 2: 0.0}], 1: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}, {0: 0.1, 1: 0.22, 2: 0.0}], 2: [{0: 0.0, 1: 0.12, 2: 0.1}, {0: 0.12, 1: 0.0, 2: 0.22}, {0: 0.1, 1:0.22, 2: 0.0}]}

这很丑陋,但是根据我们正在访问的节点来重新表述它,它是这样的:

routesdict [0]
routesdict [0, 1] [0, 1]
routesdict [0, 1, 2]  [0, 1, 2] [0, 1, 2]
Final out: [0, 1, 2]  [0, 1, 2] [0, 1, 2]

对于三节点图,如果最大距离足够高以完成每条可能的路线,我希望输出看起来更像这样:

All possible routes*: [0], [0,1], [0,1,2], [0,2], [0,2,1]
*If we must start at node 0.

================

现在,我想我看到了问题,但我无法完全考虑解决它。问题是我要保留“已访问”列表的身份,而不是删除“已访问”的当前值,然后继续处理。

所以第一次通过递归,routesdict[0] 被定义为“已访问”,并且它正确地将节点 [0] 作为第一条路由。但是当visited被改变时,routesdict[0]被更新,现在它显示[0,1]。

这与阻止函数执行我想要的递归的原因相同,这就是为什么它给了我三个可能的路线,而不是我期望的五个。

那么,有没有一种很好的方法可以在进行更深入的递归时保留我的“已访问”列表,但又不让该列表追溯应用于世界其他地方?

感谢阅读!

编辑:

我已经解决了通过将线路更改为将路线放入 routesdict 的问题

routesdict[entry_no] = visited[:]

但是对于没有访问过的列表破坏我的递归,我更加一无所知!

【问题讨论】:

    标签: python list recursion graph


    【解决方案1】:

    您的两个问题都是由同一件事引起的:Python 通过引用而不是值传递列表。

    首先,简而言之,这意味着什么:

    当您使用 a 作为 int 调用 foo(a) 时,在 foo() 内部,您只会得到 a 的值,而不是它在内存中的实际位置。你在纸上写了a,然后显示foo(),“这是a,写下来。”

    但是,当您使用b 作为列表或对象调用bar(b) 时,您不会获得b 的值,而是获得b 本身,即内存位置。你的纸上还有b,但你对bar()说,“嘿,b 非常复杂,可能不值得复制到一张新纸上。你可以分享我的论文。”这对于防止您的程序非常缓慢非常有用,但是——正如你所经历的——这意味着bar()b 所做的任何更改都会在任何地方更改b

    要解决您的问题,您应该传递您不想更改的对象的副本。在将visited 添加到routesdict 时,您已经知道了这一点,但实际上您应该这样做

    find_all_routes(graph[i], graph, willing_to_travel - cur_node[i], visited[:], routesdict)
    

    这意味着每次调用 find_all_routes() 都会获得自己的 visited 个人副本。

    【讨论】:

    • 非常感谢!很干净的答案。我只是无法完全理解它。当我只需要按三个键时,我花了几个小时试图让它工作,这有点令人沮丧,但是嘿,这就是生活!
    • 完全。这就是为什么对于任何打算从事编程职业的人来说,在某个时候使用低级语言工作是一个好主意。你开始看到很多以前没有看到的东西。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 2017-05-06
    • 1970-01-01
    • 2015-08-11
    相关资源
    最近更新 更多