我怎样才能有效地找到在预算范围内并最大化效用的活动子集?

Posted

技术标签:

【中文标题】我怎样才能有效地找到在预算范围内并最大化效用的活动子集?【英文标题】:How can I efficiently find the subset of activities that stay within a budget and maximizes utility? 【发布时间】:2011-07-29 14:31:32 【问题描述】:

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


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

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

我所做的研究表明了一种幼稚的方法:

定义powerset 对于幂集的每个元素,根据不在集合中的项目计算其效用 选择效用最高的元素

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

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

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

【问题讨论】:

很遗憾,这是 NP 完全算法:en.wikipedia.org/wiki/Knapsack_problem,因此您不太可能找到快速算法。 这听起来就像我的背包问题。您的问题与背包问题有何不同?请帮我理解其中的区别,我们可以谈谈代码(如果是背包问题,网上有很多文献)。 @Henrik:你的信息很好,但请注意,OP 只需要一个指数算法,这很好。 @Adam 集合有多大? 2^n 是巨大的,即使在优化之后它也可能很糟糕。另外,我发现您的问题类似于我之前回答过的问题:***.com/questions/6629581/… OP 是否需要快速算法无关紧要。如果他的问题是背包问题,那么简单阅读***和一些链接就会比我们任何人在合理的时间内说的更多。 【参考方案1】:

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

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

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

【讨论】:

伪多项式可能会很好,因为对象的数量可能很大(大n),但就在给定时间可能适合预算的数量而言,这可能更有限(即我站在沃尔玛的背包非常小)。【参考方案2】:

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

注意Backtracking。这对应于您的观察,一旦您将1, 2, 3, 4 作为解决方案划掉,1, 2, 3, 4 u n 就不值得一看。 应用Dynamic Programming 技术。 明确您的实际要求: 也许您不需要最佳集?一个好的会做吗?我不知道是否有一种算法可以在多项式时间内提供良好的解决方案,但很可能有。 也许您不需要一直最好的设置?使用随机算法,您可以在多项式时间内解决一些NP-问题,所有执行的失败风险为 1%(或任何您认为“足够安全”的)。

(记住:知道停止问题无法解决是一回事,但构建一个程序来确定“hello world”实现是否会无限期运行是另一回事。)

【讨论】:

你在上面问过,但我根本不明白你最后的括号里的句子。至于你的问题,我认为我拥有的是经典的 0-1 背包。我的问题可能有很大的 n,但预算很小,因此伪多项式时间实现可能会起作用。我必须在一些示例数据集上进行原型设计才能确定。【参考方案3】:

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

它似乎会在伪多项式时间内执行:活动数量呈多项式,预算范围内的活动数量呈指数级。

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

【讨论】:

以上是关于我怎样才能有效地找到在预算范围内并最大化效用的活动子集?的主要内容,如果未能解决你的问题,请参考以下文章

我怎样才能有效地洗牌?

我怎样才能有效地做到这一点? [关闭]

我怎样才能准确地找到我的代码签名身份是啥?

我怎样才能有效地计时一个只有几个周期长的函数的执行时间?

怎样进行有效的知识管理

给定一个旋转的排序数组,我怎样才能找到该数组中的最大值?