可以使用什么算法以不同的方式将不同大小的矩形打包成最小的矩形?

时间:2009-07-31 16:01:08

标签: algorithm packing

我有一堆矩形物体需要打包到最小的空间(这个空间的尺寸应该是2的幂)。

我知道各种打包算法会将这些项目尽可能地打包到给定的空间中,但在这种情况下,我需要算法来计算出该空间应该有多大。

例如说我有以下矩形

  • 128 * 32
  • 128 * 64
  • 64 * 32
  • 64 * 32

它们可以装入128 * 128空间

 _________________
|128*32          |
|________________|
|128*64          |
|                |
|                |
|________________|
|64*32  |64*32   |
|_______|________|

然而,如果还有160 * 32和64 * 64,则需要256 * 128空间

 ________________________________
|128*32          |64*64  |64*32  |
|________________|       |_______|
|128*64          |       |64*32  |
|                |_______|_______|
|                |               |
|________________|___            |
|160*32              |           |
|____________________|___________|

哪些算法能够打包一堆矩形并确定容器所需的大小(功率为2,每个维度的给定最大大小)?

8 个答案:

答案 0 :(得分:84)

答案 1 :(得分:65)

快速而肮脏的首次通过解决方案始终是一个很好的解决方案,作为比较,如果没有别的。

从大到小的贪婪安置。

将最大的矩形放入您的打包区域。如果它无法放在任何地方,请将其放置在尽可能少地延伸包装区域的位置。重复,直到你完成最小的矩形。

它根本不是完美的,但它很容易且基线很好。它仍然可以完美地包装您的原始示例,并为第二个提供相应的答案。

答案 2 :(得分:19)

看看packing problems。我认为你的产品属于'2D垃圾箱包装'。您应该能够从解决方案中学到很多东西以及其他包装问题。

另见:Packing rectangular image data into a square texture.

答案 3 :(得分:17)

关于这个问题的文献很多。一个好的贪心启发式是在第一个可用位置朝向容器的底部和左侧放置从最大区域到最小区域的矩形。想象重力将所有物品拉到左下角。有关此谷歌“Chazelle左下方包装”的描述。

对于最佳解决方案,最先进的技术可在几秒钟内打包超过20个矩形。 Huang有一个algorithm,它将找到最小的封闭边界框的问题与决定一组矩形是否适合特定尺寸的边界框的问题分开。你给他的程序一组矩形,它告诉你打包它们所需的最小的封闭边界框。

对于你的情况,你的外环应该从最小可能的边界框向上迭代(宽度和高度连续增加2的幂)。对于每个边界框,测试是否可以找到矩形的包装。你会得到一堆“不”的答案,直到第一个“是”答案,这将是最佳解决方案。

对于算法的内循环 - 对特定大小的边界框回答“是”或“否”的循环,我会查找黄色参考并实现他的算法。他在基本算法之上包含了很多优化,但你只需要基本的肉和土豆。由于您希望在搜索过程中的每个分支点处理旋转,因此只需在两次旋转都不会产生解决方案的情况下尝试旋转和回溯。

答案 4 :(得分:8)

我非常确定这是an NP-hard problem,因此,对于最佳解决方案,您必须实现一种尝试每种可能组合的回溯算法。

好消息是,由于需要在有限的2D空间中打包2D矩形,您可以在早期修剪很多可能性,因此可能不会那么糟糕。

答案 5 :(得分:2)

你需要的是什么 https://github.com/nothings/stb/blob/master/stb_rect_pack.h

样品:

stbrp_context context;

struct stbrp_rect rects[100];

for (int i=0; i< 100; i++)
{
    rects[i].id = i;
    rects[i].w = 100+i;
    rects[i].h = 100+i;
    rects[i].x = 0;
    rects[i].y = 0;
    rects[i].was_packed = 0;
}

int rectsLength = sizeof(rects)/sizeof(rects[0]);

int nodeCount = 4096*2;
struct stbrp_node nodes[nodeCount];


stbrp_init_target(&context, 4096, 4096, nodes, nodeCount);
stbrp_pack_rects(&context, rects, rectsLength);

for (int i=0; i< 100; i++)
{
    printf("rect %i (%hu,%hu) was_packed=%i\n", rects[i].id, rects[i].x, rects[i].y, rects[i].was_packed);
}

答案 6 :(得分:0)

一般的解决方案是非平凡的(数学说完全不可能) 一般来说,人们使用遗传算法来尝试可能的组合,但是你可以通过先放入最大的形状然后尝试不同的位置来完成下一个最大的形状,以此类推。

答案 7 :(得分:0)

我使用的是以下一种:

https://codereview.stackexchange.com/questions/179565/incremental-2d-rectangle-bin-packer?newreg=cce6c6101cf349c58423058762fa12b2

它实现了断头台算法,并要求输入一个维度,然后尝试优化另一个维度(您也可以在代码中进行很小的更改来设置最大值)。也许,如果您尝试使用两个值的不同幂次,它将为您工作。

无论如何它都不是最佳选择,但是它体积小,可移植(仅.h),并且除了C ++和STL之外没有其他依赖项。