从具有限制的列表中选择加权项目

时间:2018-12-25 11:26:42

标签: python

我有一个权重列表,其中每个索引代表一件物品的重量。

Weights = [0.3, 0.7, 0.1, 0.3, 0.1, ...]

每个项目都有一个碰撞项目列表,因此,如果选择项目0,则不能选择项目1。

Item_0 = [0,1,3,7]
Item_1 = [1,5,6,8]

所有项目的碰撞次数相同。

目标是在记住碰撞的同时挑选N个物品,并最大程度地增加所挑物品的重量。

最简单,最Python化的方法是什么?

最初,我认为贪婪的方法会起作用(按权重降序排列),但这种方法无效,我唯一能想到的其他解决方案是找到N个项目的所有可能组合(无碰撞)并计算总数重量。

贪婪算法(给出错误的结果):

def pickTop_K(weights, collision_dict):
    ret = []

    while len(ret) < k:

        index = np.argmax(probs)
        ret.append(index)

        collisions = collision_dict[index]
        weights[collisions] = 0

        if np.max(weights) == 0:
            break

    return ret

1 个答案:

答案 0 :(得分:0)

我很确定这个问题是NP问题。

但是,有一种方法可以解决此问题,同时限制您要做的工作如下。

首先,按权重降序对顶点进行排序。

然后进行A *搜索。也就是说,您有一个优先级队列,该队列始终返回最高优先级选项。一组选择的优先级是选择的总权重加上选择下几个顶点的权重的上限。

伪代码看起来像这样。

create priority queue paths
add to paths an empty set with weight the sum of the first n items.
while paths is not empty:
    take the top path from the queue.
    If the path is a set of n choices:
        that is your answer, return it
    else:
        Look for the next element that could or couldn't be added.
        If you found it:
            Add an option to the queue where you choose it
            Add an option to the queue where you don't choose it
        Else:
            This is a dead end.  Pass.

我最好的猜测是,可能最好对上限进行最佳估计。也就是说,您实际上找到了与任何现有选择都不冲突的顶部顶点,并对它们求和以得出一个好的上限。此操作很昂贵,但会减少分支。期权的指数增长来自分支机构-早期修剪分支机构值得投资。

如果贪婪的选择有效,该算法将很快找到它。如果接近贪婪选择的东西起作用,则不应有太多的回溯。但是,如果您不走运,这将占用指数空间和内存。 (但是,如果实际上它是NP困难的,则不能指望做得更好。)