帮助通过连接节点找到最长的非重复路径 - Python

时间:2010-03-22 20:00:49

标签: python pygame

我一直在研究这个问题几天但没有成功。基本上,我有一堆以2D矩阵排列的节点。每个节点有四个邻居,除了矩阵的边和角上的节点,它们分别有3个和2个邻居。想象一下,在一个矩形区域中并排放置了一堆方卡 - 该项目实际上模拟了一种卡片/棋盘游戏。

每个节点可能连接也可能没有连接到它周围的节点。每个节点都有一个函数(get_connections()),它返回它所连接的节点周围的节点(因此返回0到4个节点的任何地方)。每个节点还具有“索引”属性,其包含它在板矩阵上的位置(例如,“1,4” - >第1行,第4列)。我想要做的是在给定特定“开始”节点的情况下找到连接节点的最长非重复路径。

我上传了几张图片,可以很好地了解我要做的事情:

www.necessarygames.com/junk/10-days-problem-01.jpg http://www.necessarygames.com/junk/10-days-problem-01.jpg

www.necessarygames.com/junk/10-days-problem-02.jpg http://www.necessarygames.com/junk/10-days-problem-02.jpg

在两张图片中,突出显示的红色卡片被认为是包含最左上方卡片的连接卡片的最长路径。但是,您可以在两张图片中看到应该在路径中留下的几张卡片(第一张图片中是罗马尼亚和马尔代夫,第二张图片中是希腊和土耳其)

这是我目前用来寻找最长路径的递归函数,给定一个起始节点/卡:

def get_longest_trip(self, board, processed_connections = list(), 
                     processed_countries = list()):
    #Append this country to the processed countries list,
    #so we don't re-double over it
    processed_countries.append(self)
    possible_trips = dict()
    if self.get_connections(board):
        for i, card in enumerate(self.get_connections(board)):
            if card not in processed_countries:
                processed_connections.append((self, card))
                possible_trips[i] = card.get_longest_trip(board, 
                                                          processed_connections, 
                                                          processed_countries)
        if possible_trips:       
            longest_trip = []
            for i, trip in possible_trips.iteritems(): 
                trip_length = len(trip)
                if trip_length > len(longest_trip):
                    longest_trip = trip
            longest_trip.append(self)         
            return longest_trip
        else:
            print
            card_list = []
            card_list.append(self)
            return card_list
    else:
        #If no connections from start_card, just return the start card 
        #as the longest trip
        card_list = []
        card_list.append(board.start_card)
        return card_list

这里的问题与processed_countries列表有关:如果你查看我的第一个截图,你可以看到发生的事情是当乌克兰出现时,它看了两条可能的最长路径选择(Maldova-Romania ,或者土耳其,保加利亚),看到他们都是平等的,并且不分青红皂白地选择了一个。现在,当匈牙利出现时,它不能试图通过罗马尼亚(最长的路径实际上是这条路径),因为罗马尼亚已经被加入了乌克兰的加工国家名单。

对此的任何帮助都非常感谢。如果你能找到我的解决方案,递归与否,我很乐意为你捐赠一些$$。

我已将完整的源代码(Python 2.6,需要Pygame 1.9)上传到:

http://www.necessarygames.com/junk/planes_trains.zip

相关代码位于src / main.py中,该代码全部设置为运行。

3 个答案:

答案 0 :(得分:6)

你知道图中longest path problem的周期是NP难吗?

答案 1 :(得分:2)

  

...罗马尼亚已被乌克兰列入processed_countries列表。

为每个图形路径使用单独的processed_countries列表。他们说一个代码示例值得千言万语,所以我已经改变了一些代码(未经测试):

def get_longest_trip(self, board, processed_countries = list()):
    # see https://stackoverflow.com/questions/576988/python-specific-antipatterns-and-bad-practices/577198#577198
    processed_countries = list(processed_countries)
    processed_countries.append(self)

    longest_trip = list()
    if self.get_connections(board):
        possible_trips = list()
        for card in self.get_connections(board):
            if card not in processed_countries:
                possible_trips.append(card.get_longest_trip(board, 
                                                            processed_countries))
        if possible_trips:
            longest_trip = max(possible_trips, key=len)
            longest_trip.append(self)

    if not longest_trip:
        longest_trip.append(self)
    return longest_trip

无关紧要的事项:

Traceback (most recent call last):
  File "main.py", line 1171, in <module>
    main()
  File "main.py", line 1162, in main
    interface = Interface(continent, screen, ev_manager)    
  File "main.py", line 72, in __init__
    self.deck = Deck(ev_manager, continent)
  File "main.py", line 125, in __init__
    self.rebuild(continent)  
  File "main.py", line 148, in rebuild
    self.stack.append(CountryCard(country, self.ev_manager))
  File "main.py", line 1093, in __init__
    Card.__init__(self, COUNTRY, country.name, country.image, country.color, ev_manager)  
  File "main.py", line 693, in __init__
    self.set_text(text)
  File "main.py", line 721, in set_text
    self.rendered_text = self.render_text_rec(text)  
  File "main.py", line 817, in render_text_rec
    return render_textrect(text, self.font, text_rect, self.text_color, self.text_bgcolor, 1)       
  File "/home/vasi/Desktop/Planes and Trains/src/textrect.py", line 47, in render_textrect
    raise TextRectException, "The word " + word + " is too long to fit in the rect passed."
textrect.TextRectException: The word Montenegro is too long to fit in the rect passed.

源包中有16个不同的 bak 文件。十六。 Sixteeeen。考虑一下并开始使用version control.

答案 2 :(得分:0)

蛮力方法:

  1. 创建深度优先连接列表。存储列表L及其长度T。

  2. 对于此列表的每个连接:

    • 推全图
    • 删除连接。
    • 创建深度优先连接列表。
    • 如果列表长于T:将T设置为length并列出为L,则递归调用2.
    • Pop Whole Diagram。
    • 返回
  3. 这应该为连接这些节点的所有可能方式创建泛洪填充样式解决方案。