我有一个数组,其中包含不同大小的材料列表:{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);
}
}
答案 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应该是一个更容易实现的目标。