Python中列表中最长的元素链

时间:2012-05-11 09:19:53

标签: python longest-path

我有一份国家名单,我希望拥有最长的国家道路,每个国家的选择必须以结束前一个元素的相同字母开头

nations = ['albania','andorra','austria','belarus','belgium','bosnia and herzegovina',
      'bulgaria','croatia','czech republic','denmark','estonia',  
      'finland','france','germany','greece','hungary',
      'iceland','ireland','italy','latvia','liechtenstein','lithuania','luxembourg',
      'macedonia','malta','moldova','monaco','montenegro','netherlands', 
      'norway','poland','portugal','romania','russia',  
      'san marino','serbia','slovakia','slovenia','spain','sweden', 'switzerland',
      'ukraine','united kingdom','vatican city'] 

chain('spain')
>>>['spain', 'netherlands', 'slovenia', 'andorra', 'austria', 'albania']

我试过这种方式,但它不起作用

def chain(naz):
    initial = naz[-1]
    initials=[]
    res = set()
    res.add(naz)
    for i in nations:
        if i.startswith(initial):
            initials.append(i)
    for j in initials:
        nations.remove(j)
        res.add(j)
        chain(j)
    return res

有什么建议吗?

4 个答案:

答案 0 :(得分:5)

以下是一些评论:

  • 你希望返回一条路。所以它是一个有序的集合不是吗?您可能不应该为res使用set,因为set是无序的
  • 你知道la length还是返回的路径?不,你没有。所以你可能需要一个while某处
  • 只有当我从整个初始单词开始时,
  • i.startswith(initial)才是真的。你可能不想要这个
  • 您尝试使用recurcive方法。但是,您不收集结果。
  • 目前,重新召唤的呼叫毫无用处
  • nations是一个全局变量,很糟糕

修改

您的评论中描述的错误可能会发生,因为您的重复调用是在j循环中。重复呼叫可以删除国家的元素,这些元素也可能存在于首字母中。所以你试图不止一次地删除它们,这引起了一个例外。你可能想把chain(j)放在循环之外(并且可能使用它的返回值?)

答案 1 :(得分:5)

我也去了递归下降。不确定动态编程是否适合这种情况,因为列表会随着我们的进行修改。在调用链之前,稍微更紧凑并且不需要从列表中删除。 : - )

def chain(start, countries):
    remaining = list(countries)
    del remaining[remaining.index(start)]
    possibles = [x for x in remaining if x[:1] == start[-1:]]
    maxchain = []
    for c in possibles:
        l = chain(c, remaining)
        if len(l) > len(maxchain):
            maxchain = l
    return [start] + maxchain

这样打电话。 : - )

>>> chain('spain', nations)
['spain', 'netherlands', 'serbia', 'albania', 'andorra', 'austria']

答案 2 :(得分:2)

作为旁注,你的问题是NP完全的(意味着它没有“快速”多项式时间解决方案。)它可以解决小问题,但很快就会变得非常困难。

您的问题可以被视为longest-path problem on a directed graph

  • 绘制directed graph,每个单词(国家/地区)表示为顶点。
  • 对于每对单词w1w2,如果w1 -> w2的最后一个字母与{{1}的第一个字母相同,则绘制边w1 }}。
  • 如果w2的最后一个字母与w2->w1的第一个字母相同,也会从w2绘制反边。
  • 找到maximum-length path - 包含最多顶点的简单路径。 (在这种情况下,“简单”表示“不包括任何顶点多次。”)

以下是水果和蔬菜列表的示例图:w1

Word DAG Example

此图表可能包含周期(例如,此图表有一个周期Apple, banana, eggplant, kiwifruit, orange, oregano, tangerine, zucchiniThe longest path problem for directed graphs containing cycles is NP-complete.因此,此问题没有多项式时间解决方案。

这并不意味着你不能比蛮力更好。 There's a dynamic programming algorithm将复杂性从eggplant -> tangerine -> eggplant -> tangerine....(因子,非常坏)降低到O(n!)(超指数,仍然很差,但比因子更好。)

答案 3 :(得分:1)

这是一种天真的递归方式......我觉得你可以使用动态编程,它会更好

def chain(start,options):
    #start is the starting word
    #options are the words left

    next_options = [country for country in options if country[0] == start[-1]]

    #if theres no options, return the single
    if not next_options:
        return [start]

    #otherwise, return best chain out of the next option
    best_chain = None
    longest_chain = 0

    for option in next_options:

        new_options = options[:]
        new_options.remove(option)

        possible_chain = chain(option,new_options)

        if len(possible_chain) > longest_chain:
            best_chain = possible_chain
            longest_chain = len(possible_chain)

    return [start] + best_chain