我遇到的问题基本上可以解决以下问题。考虑一组n个箱子,每个箱子都有一个重量(一个加权值'可能 - 我不是在谈论箱子的物理重量),最小值(编辑:门槛) )内容和最大内容。目标是在所有箱子中分配一定量的x,使得每个箱子中的数量与该箱子的重量成比例,但仍然在该箱子的约束内(即,不低于最小箱子(编辑) :至少阈值),不超过最大值)。任何低于最小值(编辑:阈值)或超过最大值的东西都应该在其他箱子中重新分配。
天真的实现将在第一轮中按比例分配x,不超过任何一个bin的最大值;将任何多余的东西带到下一轮并重复直到x分布;然后它会检查所有箱子,看看是否满足最低限度;那些不符合最低要求的垃圾箱将被清空,其内容总计为一定数量,将在所有垃圾箱中重新分配,依此类推,直到满足所有约束并分配x。
然而,这个算法在运行时是二次的,而且我已经看到了即使在最坏的情况下也不会耗尽我的计算预算的真实数据集。所以,我的问题是 - 有没有人认识到这个问题是一个已知的优化问题?我迷失在文学的海洋中,我想我不是用正确的术语来寻找它。当然,我也很开心(实际上,更开心:))直接提示如何以更有效的方式解决这个问题。
编辑:我刚刚发现我上面使用了错误的术语 - 虽然示例没问题。我在尝试解决这个问题时使用了错误的术语,导致(至少某些)导致我提出这个问题的混乱。无论哪种方式,它说“最低”'在上面,它应该读取阈值'。因此,当bin的阈值为5时,它应该仅在超过5时分配给该bin;如果没有,金额应按比例分配给其他箱柜。我已经调整了上面的文字来表明这一点,但它没有帮助解决问题的可读性 - 不确定编辑指南在这里的问题是什么,因为直接将其更改为正确的版本将使评论没有任何意义。
答案 0 :(得分:0)
让我先解决一下我之前误解的问题,其中允许的答案必须将每个垃圾箱填满其最小数量。
首先检查您的金额x是否大于所有箱柜的最大容量之和,或者小于最小容量的总和。如果是这种情况,则在当前选择的箱柜下没有好的解决方案。
对于每个仓计算标准化的最小和最大数量 - 当前最小和最大数量除以该仓的重量。
考虑使用(当前未知的)魔法数量q分配到分档。如果标准化min> q,将垃圾箱填到最低限度。如果标准化最大值< q,将垃圾箱填满最大值。否则用重量* q填充垃圾箱。对于非常低的q值,我们得到绝对最小总内容。对于非常高的q值,我们得到绝对最大总内容。 q的中间值之一应与您想要的总内容相匹配。在此值处,中间箱具有零误差,并且最小和最大箱数与其理想填料接近,因为约束将允许它们。
作为q的函数,分布的总量是单调递增的分段线性,在归一化的最小值和最大值处改变斜率。如果您在时间O(n log n)中计算和排序这些断点,您可以进行二进制搜索以找到断点,这些断点仅在目标数量的上方和下方,每个猜测的总成本n和所需的对数猜测。然后使用线性插值来精确找到q的正确值。
或者,如果您将标准化的最大值和最小值排序到一个数组中,我认为您可以跟踪增加q时分配量的增加情况。从最低的q开始,其中分配的金额是所有最小值的总和。这里的梯度是最低最小箱的重量。当你通过其他最小值时,渐变会增加它们的重量。当你开始传递最大值时,渐变会减少它们的重量。沿着此阵列扫描,您可以找到分配金额所需数量的地方,而主要成本是对合并标准化最大值和最小值进行排序的成本。
我们现在有一个用于填充箱子的算法,当每个箱子必须至少达到其最小数量时。这种约束是不正确的,事实上我们可以识别何时出现这种情况 - 当最小数量的总和高于目标数量时,或者当某个数据库最终超过其公平份额时。
当算法出错时,我们可以使用与原始天真解决方案相同的策略 - 如果存在最小值过大的箱子,则从一个箱子中移除一些箱子,如果我们没有足够的空间则放回一些箱子(我不知道这是否是正确答案,但我认为它至少可以接受,因为它在天真的解决方案中使用)。我们从标准化最小数量最大的箱子开始移除箱子。同样,因为我们可以对二进制文件进行二进制切割,所以我们只需要log n次传递 - 我认为我们想要使用尽可能多的二进制文件。
这为我们提供了一个外部循环,即log n遍历原始解决方案。如果原始解决方案需要时间n log n,并且每次成本为n(log n)^ 2时我们从头开始重复。如果因为初始排序而使用唯一log n因子的备用,我们只需要在开始时进行一次初始排序,并且每次内部通过仅花费O(log n)。这给我们的总成本为O(n log n)。