一维嵌套算法

7
什么是将一维长度嵌套到预定义库存长度的有效算法?
例如,如果您需要以下数量和长度的钢筋:
5 x 2米
5 x 3米
5 x 4米
并且这些可以从10米长的钢筋中切割。如何计算切割10米长钢筋的图案,以使使用最少的钢筋条数?
此外,如何将多个库存长度纳入算法?
我有点时间来解决这个问题,所以我将写下我是如何解决的。希望对某些人有用。我不确定是否可以像这样回答自己的问题。如果更合适,管理员可以将其更改为答案。
首先感谢所有回答过我的人。这指引我找到了适当的算法; the cutting stock problem
这篇文章也很有用; "Calculating a cutting list with the least amount of off cut waste"
好的,进入解决方案。
我将在我的解决方案中使用以下术语;
  • 库存: 一段将被切割成较小块的材料长度
  • 切割: 从库存中切下的一段材料。可以从同一块库存中取多次切割。
  • 废料: 在所有切割完成后留在库存中的材料长度。
解决问题有三个主要阶段,
  1. 确定所有可能的切割组合
  2. 确定每块材料可以采用哪些组合
  3. 找到最优的切割组合混合。

步骤1

使用N个切割,有2^N-1个唯一的切割组合。这些组合可以表示为二进制真值表。

其中A、B、C是独特的切割;

A B C | Combination
-------------------
0 0 0 | None
0 0 1 | C
0 1 0 | B
0 1 1 | BC
1 0 0 | A
1 0 1 | AC
1 1 0 | AB
1 1 1 | ABC

使用一些位运算符的for循环可以快速创建每个切割组合的分组。

对于较大的N值,这可能会非常耗时。

在我的情况下,存在多个相同的切割实例。这产生了重复的组合。

A B B | Combination
-------------------
0 0 0 | None
0 0 1 | B
0 1 0 | B (same as previous)
0 1 1 | BB
1 0 0 | A
1 0 1 | AB
1 1 0 | AB (same as previous)
1 1 1 | ABB

我能利用这种冗余来减少计算组合的时间。我将重复的切割分组,并计算该组的独特组合。然后将这个组合列表附加到第二组中的每个独特组合中,以创建一个新组。
例如,对于切割 AABBC,过程如下。
A A | Combination
-------------------
0 1 | A 
1 1 | AA

将此组称为X。

将X附加到唯一的B实例中,

B B X | Combination
-------------------
0 0 1 | A 
      | AA
0 1 0 | B
0 1 1 | BA
      | BAA
1 1 0 | BB 
1 1 1 | BBA
      | BBAA

把这个组称为Y。

将Y添加到C的唯一实例中,

C Y | Combination
-----------------
0 1 | A 
    | AA
    | B
    | BA
    | BAA
    | BB 
    | BBA
    | BBAA 
1 0 | C
1 1 | CA 
    | CAA
    | CB
    | CBA
    | CBAA
    | CBB 
    | CBBA
    | CBBAA 

这个例子产生了17种独特的组合,而不是31种(2^5-1)。几乎节省了一半的时间。
一旦所有的组合都被确定了,就是时候检查它们如何适应库存了。
第二步
这一步的目的是将第一步中确定的切割组合映射到可用的库存尺寸上。
这是一个相对简单的过程。对于每个切割组合,
   calculate the sum of all cut lengths.
   for each item of stock, 
        if the sum of cuts is less than stock length,
            store  stock, cut combination and waste in a data structure.
            Add this structure to a list of some sort.

这将导致一个有效的嵌套切割组合列表。虽然不一定需要存储废料,因为可以通过切割长度和库存长度来计算,但是存储废料会减少第三步中所需的处理。

第三步

在此步骤中,我们将确定产生最小废料的切割组合。这基于步骤2生成的有效嵌套列表。

在理想情况下,我们将计算所有可能性并选择最佳解决方案。对于任何非平凡的切割集,计算所有可能性将需要很长时间。我们只能满足于非最优解决方案。有各种算法可用于完成此任务。

我选择了一种方法,该方法将寻找最少废料的嵌套。它将重复此操作,直到所有切割都已计算。

从三个列表开始

  • cutList:所有所需切割(包括重复项)的列表。
  • nestList:步骤2生成的嵌套列表。这是按最少废料到最多废料排序的。
  • finalList:最初为空,这将存储将输出给用户的切割组合列表。

方法

pick nest from nestList with the least waste
  if EVERY cut in the nest is contained in cutList
     remove cuts from cutList
     copy this nest into the finalList
  if some cuts in nest not in cutList
      remove this nest from nestList             
repeat until cutlist is empty

通过这种方法,我成功地将一些典型测试数据的总浪费降低了约2-4%。希望有一天我能够重新审视这个问题,并尝试实现延迟列生成算法。这应该会得到更好的结果。

我希望这对其他遇到这个问题的人有所帮助。

大卫


这个问题看起来非常像一道作业题... - Nick Fortescue
也许这不是作业 - 这非常像我在1990年左右为一个实际的工业问题编写程序。 - DarenW
我使用了不同的算法。其结果可以在http://wood-cut.rhcloud.com上看到。它并不能提供最优解,因为这需要一种枚举方法,但是它可以提供一个可接受的解决方案。我见过一些软件以50美元以上的价格提供此功能,并使用遗传算法,但不能保证最优解,有时甚至比http://wood-cut.rhcloud.com提供的结果更差。我正在努力优化我的网站,并将在有时间时编写该算法。 - Gaurav Sharma
4个回答

8
实际上,还有一个更具体的问题适用:切割库存问题
切割库存问题是一个优化问题,或者更具体地说,是一个整数线性规划问题。它源于许多工业应用。想象一下,你在一家造纸厂工作,有许多卷固定宽度的纸等待切割,但不同的客户需要不同数量和尺寸的纸卷。你应该如何切割这些纸卷以最小化浪费(剩余物的数量)?
之所以比装箱问题更适用,是因为你试图最小化浪费,而不是最小化“箱子”的数量。从某种意义上讲,装箱问题是切割库存问题的反向问题:如果你有一些钢材长度,要怎样重新组合它们,使得它们能够在一定大小的限制下尽可能少地变成条形材料?

5

嘿,plinth,回答得不错。也许值得编辑你的回答并展示出来,而不是留在评论中。 - Nick Fortescue

1

0
几年前解决了一个类似的问题。最后我使用了遗传算法。对于小问题来说,这可能有些大题小做。尽管编写这个程序有些有趣,但同时也有些无聊,因为那时候还是在16位的时代。
首先,它列出了所有可能的方式来切割一根10英尺的原材料,利用给定的长度。对于每种方式,记录了所浪费的材料量。(虽然这是快速计算,但存储以便日后查找更快)。然后它查看所需零件列表。在一个循环中,它会从切割列表中选择一种切割库存的方式,该方式不会切割超过所需数量的任何尺寸的更多零件。贪心算法会选择最小化浪费的方案,但有时通过放宽限制可以找到更好的解决方案。最终,遗传算法进行了选择,“DNA”是一组切割方式,这些方式在过去的解决方案中表现良好。
所有这些都是在互联网之前的时代完成的,通过巧妙的实验和探索来完成。如今,可能已经有一些.NET或Java库来完成它,这将是一个黑盒子,但那样会更少乐趣和教育意义,不是吗?

你能指点我一下吗?因为我想实现这个(遗传)解决方案...我尝试了蛮力法...但有时候它需要太长时间... - Diego Castro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接