如何有效地找到保持在预算范围内并最大化效用的活动子集?

时间:2011-07-29 14:31:33

标签: algorithm recursion knapsack-problem

我正在尝试开发一种算法,从较大的列表中选择一个活动子集。如果选择,则每个活动使用一定量的固定资源(即,所选活动的总和必须保持在总预算之下)。可能有多个可行的子集,从中选择的方法将基于计算未选择的活动的机会成本。


编辑:这不是0-1 knapsack problem有两个原因:

  • 背包需要权重的整数值(即消耗的资源),而我的资源消耗(即背包说法中的质量)是连续变量。 (显然,可以选择一定程度的精度并量化所需的资源,但我的bin大小必须非常小,并且W中的背包为O(2^n)
  • 我无法先验地计算机会成本;也就是说,虽然我可以评估一组给定活动的效用,或者通过向现有列表添加额外任务来评估边际效用,但我无法独立评估每个活动的适用性。

我所做的研究表明了一种天真的方法:

  

定义powerset
     对于powerset的每个元素,根据不在集合中的项目计算它的效用      选择具有最高实用程序的元素

但是,我知道有办法加快执行时间和所需的内存。例如:

  • 完全枚举一个powerset是O(2^n),但我不需要完全枚举列表,因为一旦我发现一组超出预算的任务,我知道任何添加更多任务的集合都是不可行的并且可以被拒绝。也就是说,如果{1,2,3,4}不可行,{1,2,3,4} U {n}也是如此,其中n是较大列表中剩余的任务之一。
  • 由于我只是总结职责,任务的顺序无关紧要(即{1,2,3}是否可行,{2,1,3}{3,2,1}等也是如此。
  • 我最终需要的是所选的集合,所以我可能只需要到目前为止找到的最佳效用值来进行比较。
  • 我不需要保留列表枚举,只要我能确定我已经查看了所有可行的列表。 (虽然我认为保留先前计算的可行子集的任务总和可能会加快运行时间。)

我已经说服自己一个好的递归算法会起作用,但我无法弄清楚如何定义它,即使在伪代码中(这可能是最有意义的,因为它将以几种语言实现) - 可能是Matlab用于原型设计,然后是编译语言)。

3 个答案:

答案 0 :(得分:2)

knapsack problem是NP完全的,这意味着没有有效的方法来解决问题。然而,有一个使用动态编程的伪多项式时间解决方案。有关详细信息,请参阅其上的Wikipedia section

但是,如果最大效用很大,则应该使用近似算法。一种这样的近似方案是贪婪地选择具有最大效用/成本的项目。如果预算很大并且每个项目的成本很小,那么这可以很好地解决。

编辑:由于您根据不在集合中的项目定义实用程序,因此您可以简单地重新定义成本。否定成本,然后改变一切,使你的所有价值观都是积极的。

答案 1 :(得分:1)

正如其他人所提到的,你正试图解决一些背包问题。虽然从理论上讲,你注定要失败,但在实践中你仍然可以做很多事情来提高算法的性能。以下是一些(各种各样的)想法:

  • 请注意Backtracking这与您的观察结果相符,一旦您划出{1, 2, 3, 4}作为解决方案,{1, 2, 3, 4} u {n}就不值得关注。< / LI>
  • 应用Dynamic Programming技术。
  • 明确您的实际要求
    • 也许您不需要最佳设置?一个好人会吗?我不知道是否有一种算法在多项式时间内提供了一个很好的解决方案,但可能会有。
    • 也许你不需要一直的最佳设置?使用随机算法,您可以解决一些NP - 多项式时间中的问题,并且所有执行中1%(或任何您认为“足够安全”)的失败风险。

(请记住:知道停止问题不可解决是一回事,而另一个问题是构建一个程序来确定“hello world”实现是否会以无限的方式运行。)

答案 2 :(得分:0)

我认为以下迭代算法将遍历整个解决方案集并存储任务列表,执行它们的总成本以及未执行任务的机会成本。

似乎它将在伪多项式时间内执行:活动数量的多项式和可以在预算范围内的活动数量的指数。

ixCurrentSolution = 1

initialize empty set solution {
    oc(ixCurrentSolution)        = opportunity cost of doing nothing
    tasklist(ixCurrentSolution)  = empty set
    costTotal(ixCurrentSolution) = 0
    }

for ixTask = 1:cActivities
    for ixSolution = 1:ixCurrentSolution 
        costCurrentSolution = costTotal(ixCurrentSolution) + cost(ixTask)
        if costCurrentSolution < costMax
             ixCurrentSolution++
             costTotal(ixCurrentSolution) = costCurrentSolution 
             tasklist(ixCurrentSolution)  = tasklist(ixSolution) U ixTask 
             oc(ixCurrentSolution)       = OC of tasks not in tasklist(ixCurrentSolution)
        endif
    endfor
endfor