Bin Packing - 蛮力递归解决方案 - 如何使其更快

时间:2011-11-29 12:03:31

标签: algorithm recursion bin packing

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

对于上面的数组,您可以打包3个分箱并按如下方式划分:{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);
        }
}

3 个答案:

答案 0 :(得分:5)

动态编程算法是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:按递减顺序排序,将结果存储在链表中,然后反复尝试从头开始插入项目(最大值为第一个),直到你填满垃圾箱或没有更多可以插入的项目。然后转到下一个垃圾箱,依此类推。

参考

Owen Kaser,Daniel Lemire,Tag-Cloud Drawing: Algorithms for Cloud Visualization,社会信息组织的标记和元数据(WWW 2007),2007。(相关讨论见5.1节)。

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

答案 1 :(得分:1)

在您的情况下:Bin大小= 30,总项目= 27,至少需要3个bin。 你可以尝试先适应减少,它的工作原理!

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

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

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

如果你有大件物品,可以尝试更多的事情:如果你有一个大项目,并且适合它的最大项目大于或大于任何适合的项目组合,那么组合它们是最佳的。如果有更多的空间,那么这可以重复。

总而言之,一些想法减少了将两个尺寸为4的物品装入一个或多个箱子的问题。对于更大的问题,每一点点都有帮助。

答案 2 :(得分:0)

在尽你所能减少问题之后,如果可能的话,你可以将n个项目放入k个bin中,否则放入k + 1个bin,或者放入k + 2个bin中等等。如果k个bin失败,那么你知道在k + 1箱的最佳解决方案中你会有更多的空位,这可能会删除更多的小物品,所以这是第一件事。

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

最终你需要蛮力。您可以决定:您是否尝试将所有东西都放入k箱中,或者您是否试图证明它不可能?你将有一些空的空间可以玩。假设10个大小为100的箱子和总大小为936的物品,这将留下64个空单位。如果您只将80号物品放入第一个箱子中,那么64个单元中的20个已经不见了,这使得从那里找到解决方案变得更加困难。所以你不要以随机顺序尝试。您首先尝试完全填充或完全填充的第一个bin的组合。由于小件物品可以更容易地完全装满容器,所以尽量不要在第一个箱子中使用它们,但是如果您选择的物品较少,请将它们留待以后使用。当您发现要放入垃圾箱的物品时,请尝试使用一种简单的算法来查看它们是否可以完成它。例如,如果第一个适合下降将90个单位放入第一个垃圾箱,并且您只是设置了99个单位,那么很可能这足以适应所有情况。

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