旅行推销员:通过递归获取所有可能的路径

时间:2016-04-23 18:47:17

标签: python recursion traveling-salesman

我正在尝试编写递归方法来计算旅行商问题的所有可能路径:

def allPaths(toCover, path=""):

    path = path + toCover[0]
    toCover.remove(toCover[0])

    if len(toCover)>0:
        for x in range (0, len(toCover)):
            #swop cities
            temp = toCover[0]
            toCover[0] = toCover[x]
            toCover[x] = temp
            allPaths(toCover, path)
    else :
        print path


cities = ["A", "B", "C", "D"]

allPaths(cities)

所以,我有一份城市名单。

我将列表中的第一个城市添加到当前路径。 我从城市toCover列表中删除了添加的城市。 对于列表中的每个剩余城市,我再次调用allPaths()函数。我修改了list参数,每个城市都在索引0上一次。

(我想用以下列表实例调用allPaths:

[B,C,D]
[C,B,D]
[D,C,B]

然而,当我调试这个时,城市 - toCover列表会在所有"实例"中被修改。 allPaths。这意味着,它返回第一个有效路径" ABCD",但之后不会继续,因为对于下一个呼叫,所有城市都已被删除。

我做错了什么?

我希望这个解释有些清楚......

1 个答案:

答案 0 :(得分:1)

解决方案很简单。这是因为toCover(如果你问我,我应该命名为to_cover,但是,嘿,这是你的代码^^)是一个列表。 列表是可变的,这意味着每个实例都将引用保存到原始对象,导致所有更改都在所有引用上完成的问题(好吧,它们实际上只是对对象完成,但是引用指向该对象,所以......)。

您可以通过三种方式解决问题:

  • 改为使用元组,或者只使用列表就好像它是元组一样

    您将cities = ["A", "B", "C", "D"]替换为cities = ("A", "B", "C", "D")(如果您想要一个元组),并使用toCover = toCover[1:]代替toCover.remove(toCover[0]),应该是(如果它应该< / em>修改底层对象)del toCover[0]无论如何。

    x[1:]创建一个列表或元组的片段(尽管您可以在自己的类型中为该运算符实现几乎任何内容),从而产生一个除第一个元素之外的任何元素的新实例。请参阅here(python文档缺少真正的解释,不要问我为什么)。

  • 一遍又一遍地复制列表

    这个解决方案是处理问题的常用方法,但它实际上并不是这里的方法。这通过复制列表来绕过引用:toCover = toCover[:](这应该在函数的顶部)。它创建一个包含整个列表的切片(再次:this link),有效地复制它。

  • 使用itertools.permutations做你想做的事情。 (请参阅@John Coleman对您的问题的评论)有关详细信息,请参阅python documentation

我希望我能提供帮助,

CodenameLambda