此任务类似于有界背包问题(BKP)。 我们有约300种不同的膳食,其参数如下: ID,价格,重要性/评级,类别。
例如:
id price importance type
-----------------------------
1 100 78 butter
2 50 89 milk
3 70 66 milk
4 66 50 butter
我们想要选择TOP-10最佳产品组合,但是根据具体配置,我们只想吃3种黄油,2种面包和2种牛奶。这种TOP-10组合必须具有最高的重要性。 此外,我们必须考虑可用的预算。
它与背包问题有点不同,因为我们想要TOP-10结果,而不仅仅是最好的结果。 并且同一组的每一餐/产品(例如黄油)具有不同的价格和重要性/评级。
答案 0 :(得分:1)
一种可能足够的启发式方法是使用进化算法(对于背包式问题进行编程相当容易),人口相当多,让它进化一段时间,然后采取前10个解决方案
获得可证明的前十大解决方案当然会更难(从字面上看 - 显然是NP难的)。一种方法是将其解决为最优,记录解决方案,添加约束以排除该解决方案,然后解决。重复这样做,直到获得前十大解决方案。
答案 1 :(得分:1)
我认为价格是整数且相当小,你正在考虑一些学校型DP解决方案。
在动态编程算法中,对于每个状态,我们只存储一个最佳的部分解决方案。通常我们不会在物理上存储部分解决方案:只是它的成本和一些简单的回溯信息,以便以后重建它。由于最佳子结构属性,我们不会为状态存储其他解决方案:任何成本较低的部分解决方案都会延续,这与最佳部分解决方案的相同延续更为糟糕。
为了找到 k 问题的最佳解决方案,您只需为每个DP状态存储 k 最佳部分解决方案。如果对于某些状态,根本没有 k 解决方案,则存储所有这些解决方案。为什么我们可以删除比 k 其他部分解更差的部分解决方案?因为它的任何延续都会比那些 k 更好的部分解决方案的延续更糟糕。
前进式DP中的转换照常完成。当你考虑一些状态时,你应该迭代它的所有 k 最佳部分解决方案,并尝试以各种可能的方式继续它们中的每一个(例如,是否采取新项目)。对于每个延续,请查看其状态。将延续项插入最佳部分解决方案的排序列表中。如果结果有 k + 1 部分解决方案,请删除最差的解决方案。
您肯定不希望在DP中存储部分解决方案。相反,只存储每个部分解决方案的总成本和回溯信息。回溯信息应该足以明确地确定DP中的先前部分解决方案。通过这种方式,您可以找到最佳 k 解决方案。似乎具有 k 最佳解决方案的DP解决方案需要 O(k)倍的内存和 O(k ^ 2)倍的时间(或 O(k log k))用于背包,与仅找到一个最佳解决方案相比。
在我看来,你应该用两级算法来解决你的问题:
对于单个类别,使用 W 背包大小解决DP从 N 项目列表中选择 s 项目似乎需要 O(s NW k ^ 2)时间。在步骤2中合并来自 c 类别的解决方案似乎采用 O(c W ^ 2 k ^ 2),但它可以减少到 O(c W k log(W k))如果使用平衡树进行合并。