如何在剔除坏序列时生成排列?

时间:2017-07-31 21:13:23

标签: python algorithm permutation

问题陈述:我有150个附加权重和值的对象。对象的权重可能会根据选择的顺序而改变,通常会选择约70-80个项目。我只能选择最大权重,因此一旦我找到了具有该序列的子解决方案,就需要跳过以相同序列开头的所有排列。目标是最大化价值。

我可以通过以下方式轻松创建所有排列:

from itertools import permutations
for i in permutations(list(range(150))):
    # do something with i

然而,这将创建许多我不需要检查的序列。我也可以用r来限制置换长度

from itertools import permutations
for i in permutations(list(range(150)), r=80):
    # do something with i

然而,对于非常糟糕的序列,仍然会有大量的冗余检查。此外,这可能会在“最佳”解决方案之前停止。

我可以做类似

的事情
from itertools import permutations
v = []
for i in permutations(list(range(150)), r=80):
    if v and v == i[:len(v)]:
        continue
    # do something with i
    v = i # would be some optimal subset of i

然而,由于Python仍在生成和检查序列,因此仍需要很长时间才能运行。有关如何处理此问题的任何想法?理想情况下,我可以并行运行检查。

更多背景:我正在尝试为名为Black Desert Online的游戏创建优化的资源图表(图片示例在somethinglovely.net/bdo/)。该图具有~150个资源节点,每个节点可以连接到14个根节点的子集。图上的中间节点具有与它们相关联的权重。每个城市都有可以连接的最大节点数,并且将资源节点连接到城市还有额外的重量成本。我没有成功地使用随机图生成与遗传算法相结合来“找到”最优解。此外,只是做出贪婪的选择会导致次优解决方案。我目前难以理解如何生成一个在合理的时间段内运行的强力+综合解决方案(合理的在一天内在合理的台式计算机上运行。

1 个答案:

答案 0 :(得分:1)

一次浏览库存清单,一个项目,并尝试打包有和没有该项目(两次递归)。当我们达到两点之一时报告解决方案:

  1. 不再需要考虑的项目
  2. 剩下的清单符合我们的体重预算。
  3. 通过积极的施工来处理剔除。

    代码:

    items = [
        # Description, weight
        ("petrol", 10),
        ("clothes", 8),
        ("tents", 7),
        ("beer", 16),
        ("food", 20),
        ("teddy bear", 3),
        ("tank", 25),
        ("skin lotion", 2),
        ("library", 17),
        ("mortar", 9),
        ("cut lumber", 12),
        ("sports gear", 14),
    ]
    
    limit = 20
    
    def load(inventory, max_weight, current):
    
        still_okay = [item for item in inventory if item[1] <= max_weight]
        if len(still_okay) == 0:
            # Can't add any more; emit solution and back up
            print "RESULT", current
        else:
            # If the rest of the list fits in our weight budget,
            #   take everything.
            if sum([item[1] for item in still_okay]) <= max_weight:
                print "RESULT", current + still_okay
            else:
                item = still_okay.pop()
                # recur on two branches: one each with and without this item
                load(still_okay, max_weight - item[1], current + [item])
                load(still_okay, max_weight, current)
    
    load(items, limit, [])
    

    输出:

    RESULT [('sports gear', 14), ('teddy bear', 3), ('skin lotion', 2)]
    RESULT [('cut lumber', 12), ('skin lotion', 2), ('teddy bear', 3)]
    RESULT [('cut lumber', 12), ('teddy bear', 3)]
    RESULT [('cut lumber', 12), ('tents', 7)]
    RESULT [('cut lumber', 12), ('clothes', 8)]
    RESULT [('mortar', 9), ('skin lotion', 2), ('teddy bear', 3)]
    RESULT [('mortar', 9), ('skin lotion', 2), ('tents', 7)]
    RESULT [('mortar', 9), ('skin lotion', 2), ('clothes', 8)]
    RESULT [('mortar', 9), ('teddy bear', 3), ('tents', 7)]
    RESULT [('mortar', 9), ('teddy bear', 3), ('clothes', 8)]
    RESULT [('mortar', 9), ('tents', 7)]
    RESULT [('mortar', 9), ('clothes', 8)]
    RESULT [('mortar', 9), ('petrol', 10)]
    RESULT [('library', 17), ('skin lotion', 2)]
    RESULT [('library', 17), ('teddy bear', 3)]
    RESULT [('skin lotion', 2), ('teddy bear', 3), ('tents', 7), ('clothes', 8)]
    RESULT [('skin lotion', 2), ('teddy bear', 3), ('clothes', 8)]
    RESULT [('skin lotion', 2), ('teddy bear', 3), ('petrol', 10)]
    RESULT [('skin lotion', 2), ('beer', 16)]
    RESULT [('skin lotion', 2), ('tents', 7), ('clothes', 8)]
    RESULT [('skin lotion', 2), ('tents', 7), ('petrol', 10)]
    RESULT [('skin lotion', 2), ('petrol', 10), ('clothes', 8)]
    RESULT [('teddy bear', 3), ('beer', 16)]
    RESULT [('teddy bear', 3), ('tents', 7), ('clothes', 8)]
    RESULT [('teddy bear', 3), ('tents', 7), ('petrol', 10)]
    RESULT [('teddy bear', 3), ('clothes', 8)]
    RESULT [('teddy bear', 3), ('petrol', 10)]
    RESULT [('food', 20)]
    RESULT [('beer', 16)]
    RESULT [('tents', 7), ('clothes', 8)]
    RESULT [('tents', 7), ('petrol', 10)]
    RESULT [('petrol', 10), ('clothes', 8)]