【问题标题】:Bin Packing - Brute force recursive solution - How to make it fasterBin Packing - 蛮力递归解决方案 - 如何使其更快
【发布时间】:2011-11-29 12:03:30
【问题描述】:

我有一个包含不同尺寸材料列表的数组:{4,3,4,1,7,8}。但是,bin 最多可以容纳 10 大小的材料。我需要找出包装数组中所有元素所需的最小 bin 数量。

对于上面的数组,你可以打包成 3 个 bin 并按如下方式划分:{4,4,1}, {3,7}, {8}。还有其他可能的安排也适合三个库存管道,但不能用更少的方式完成

我正在尝试通过递归来解决这个问题,以便更好地理解它。

我正在使用this DP 公式(pdf 文件的第 20 页)

考虑一个输入 (n1;:::;nk),其中 n = ∑nj 个项目
确定可以打包到单个 bin 中的 k 元组(输入的子集)的集合
即 OPT(q1;:::;qk) = 1 的所有元组 (q1;:::;qk)
用 Q 表示这个集合 对于每个 k 元组 q ,我们有 OPT(q) = 1
使用递归计算剩余值: OPT(i1;:::;ik) = 1 + minOPT(i1 - q1;:::;ik - qk)

我已经编写了代码,它适用于小数据集。但是如果将数组的大小增加到超过 6 个元素,它会变得非常慢 -- 需要大约 25 秒来解决包含 8 个元素的数组 你能告诉我算法是否有问题吗?我不需要替代解决方案 --- 只需要知道为什么这么慢,以及如何改进它

这是我用 C++ 编写的代码:

void recCutStock(Vector<int> & requests,  int numStocks)
{
 if (requests.size() == 0)
 {

     if(numStocks <= minSize)
    {
        minSize = numStocks;

    }
//   cout<<"GOT A RESULT : "<<numStocks<<endl;
        return ;
 }
 else
 {
    if(numStocks+1 < minSize) //minSize is a global variable initialized with a big val
    {
     Vector<int> temp ; Vector<Vector<int> > posBins;
     getBins(requests, temp, 0 , posBins); // 2-d array(stored in posBins) containing all possible single bin formations

    for(int i =0; i < posBins.size(); i++)
    {
        Vector<int> subResult;
        reqMinusPos(requests, subResult,  posBins[i]);  // subtracts the initial request array from the subArray
        //displayArr(subResult);


            recCutStock(subResult,  numStocks+1);


    }
    }
    else return;
 }

}

getBins函数如下:

void getBins(Vector<int> & requests, Vector<int> current, int index, Vector<Vector<int> > & bins)

{

if (index == requests.size())

{

if(sum(current,requests) <= stockLength && sum(current, requests)>0 )

        {
                bins.add(current);
            //  printBins(current,requests);
            }
            return ;
        }
        else
        {

        getBins(requests, current, index+1 , bins);
                current.add(index);
            getBins(requests, current, index+1 , bins);
        }
}

【问题讨论】:

  • 你的代码和描述是如何对应的?在 cmets 中解释每个变量的含义以及函数应该做什么。对于任何试图调查的人来说,一个独立的可编译示例会很好。另一方面,链接源声明了 O(n^(2k)) 的复杂度,其中 n 是项目的数量,k 是不同大小的数量(iiuc )。例如,有 8 个项目和 6 种不同的尺寸,这大量计算。
  • 如果你想让别人浏览你的代码,至少让它可读。使用这种格式没有人会帮助你,这是一团糟。

标签: algorithm recursion bin packing


【解决方案1】:

动态规划算法为 O(n^{2k}),其中 k 是不同项目的数量,n 是项目的总数。无论实施如何,这都可能非常缓慢。通常,在解决 NP 难题时,需要使用启发式算法来提高速度。

我建议您考虑 Coffman 等人的 Next Fit Decreasing Height (NFDH) 和 First Fit Decreasing Height (FFDH)。它们分别是 2 最优和 17/10 最优,运行时间为 O(n log n)。

我建议您先尝试 NFDH:按降序排序,将结果存储在链表中,然后重复尝试从头开始插入项目(最大值在前),直到您填满 bin 或没有更多可以插入的项目。然后转到下一个 bin 以此类推。

参考文献

Owen Kaser, Daniel Lemire, Tag-Cloud Drawing: Algorithms for Cloud Visualization, Tagging and Metadata for Social Information Organization (WWW 2007), 2007。(有关相关讨论,请参阅第 5.1 节。)

E. G. Coffman, Jr.、M. R. Garey、D. S. Johnson 和 R. E. Tarjan。面向级别的二维打包算法的性能界限。 SIAM J. Comput., 9(4):808–826, 1980.

【讨论】:

    【解决方案2】:

    但是如果将我的数组的大小增加到超过 6 个元素,它 变得非常慢——求解一个数组大约需要 25 秒 包含8个元素你能告诉我是否有什么问题吗 算法?

    使用蛮力是正常的。 Brute force does not scale at all.

    【讨论】:

      【解决方案3】:

      在您的情况下:箱大小 = 30,项目总数 = 27,至少需要 3 个箱。 您可以尝试先拟合递减,并且有效!

      更多改进方法:使用 3 个垃圾箱和 27 个尺寸单位,您将剩下 3 个单位的空间。这意味着您可以忽略大小为 1 的项目;如果你把其他的放进 3 个箱子里,它会放在某个地方。剩下 26 个尺寸单位。这意味着您将在一个垃圾箱中至少有两个单元是空的。如果你有大小为 2 的物品,你也可以忽略它们,因为它们适合。如果您有两个大小为 2 的项目,您也可以忽略大小为 3 的项目。

      您有两个大小为 7 + 3 的项目,这正是 bin 大小。总有一个最佳解决方案,这两个在同一个 bin 中:如果“7”与其他项目一起,它们的大小将是 3 或更小,因此如果它在另一个 bin 中,您可以将它们与“3”交换。

      另一种方法:如果你有 k 个项目 >= bin size / 2(此时你不能有两个项目等于 bin size / 2),那么你需要 k 个 bins。这可能会增加您最初估计的最小 bin 数量,从而增加所有 bin 中的保证空白空间,从而增加一个 bin 中剩余空间的最小大小。如果对于 j = 1, 2, ..., k 您可以将 所有 项与它们一起放入可能适合同一个 bin 的 j 个 bin 中,那么这是最佳的。例如,如果您有 8、1、1 码但没有 2 码,则箱中的 8+1+1 将是最佳选择。由于您还剩下 8 + 4 + 4,并且没有任何东西适合 8,因此仅在其 bin 中的“8”是最佳的。 (如果您有尺寸为 8、8、8、2、1、1、1 的物品,而没有其他尺寸为 2 的物品,则将它们装入三个箱子是最佳选择)。

      如果您有大件物品,可以尝试更多方法:如果您有一件大件物品,并且与之匹配的最大物品与任何适合的物品组合一样大或更大,那么将它们组合起来是最佳选择。如果有更多空间,则可以重复此操作。

      总而言之,稍微思考一下就可以将问题简化为将两个尺寸为 4、4 的物品放入一个或多个箱子中。对于更大的问题,每一点都有帮助。

      【讨论】:

        【解决方案4】:

        我已经编写了一个装箱解决方案,我可以推荐随机顺序的最佳匹配。

        【讨论】:

        • 这是一个快速的算法,但不是最优的。 This slide 将它(蓝色条)与其他算法进行比较。绿色和黄色算法更好(但更慢)。
        【解决方案5】:

        在尽你所能减少问题之后,如果可能的话,你将面临将 n 个项目放入 k 个箱子中的问题,否则放入 k + 1 个箱子中,或者放入 k + 2 个箱子中等等。如果 k 个箱子失败,那么您知道在 k + 1 个 bin 的最优解中您将有更多的空白空间,这可能会移除更多的小物品,所以这是首先要做的事情。

        然后你尝试一些简单的方法:首先适合降序,然后适合降序。我尝试了第一次适合降序的相当快速的变化:只要两个最大的项目适合,就添加最大的项目。否则,找到适合的单个项目或两个项目的最大组合,然后添加单个项目或该组合中的较大者。如果这些算法中的任何一个将您的物品放入 k 个箱子中,那么您就解决了问题。

        最终你需要蛮力。您可以决定:您是尝试将所有内容放入 k 个 bin 中,还是尝试证明这是不可能的?您将有一些空白空间可以玩。假设 10 个大小为 100 的箱子和总大小为 936 的物品,这将留下 64 个单位的空白空间。如果您只将尺寸为 80 的物品放入您的第一个垃圾箱,那么您的 64 件商品中有 20 件已经用完,这使得从那里找到解决方案变得更加困难。所以你不要按随机顺序尝试。您首先尝试将第一个垃圾箱完全或接近完全装满的组合。由于小物品更容易完全装满容器,因此您尽量不要在第一个垃圾箱中使用它们,而是将它们留到以后,当您选择较少的物品时。当您找到要放入垃圾箱的物品时,请尝试其中一种简单的算法,看看他们是否可以完成它。例如,如果 first fit downding 将 90 个单元放入第一个 bin,而您只是设法将 99 个单元放入其中,那么这很可能足以适应所有内容。

        另一方面,如果空间非常小(例如 10 个箱子,物品总大小 995),您可能想要证明无法安装这些物品。您不需要关心优化算法以快速找到解决方案,因为您需要尝试所有组合才能看到它们不起作用。显然,您需要使用这些数字将至少 95 个单位放入第一个箱中,依此类推;这可能使快速排除解决方案变得容易。如果您证明 k 个 bin 是不可实现的,那么 k+1 个 bin 应该是一个更容易的目标。

        【讨论】:

          猜你喜欢
          • 2014-03-29
          • 2015-08-10
          • 2022-01-09
          • 1970-01-01
          • 2015-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多