如何将各种长度的木材切割成标准长度的木材

时间:2016-06-18 20:31:32

标签: python algorithm

我正在尝试编写一个程序来计算从标准2"中删除一些小块木材的最有效方法。按4"由8'片。我在搜索用于此的算法时遇到问题。请帮忙!我使用Python但只想了解算法如何工作的一般概念。

情况是,我需要做一些短于8&#39的木材切割,并且长度不同。我想从最小数量的8'中切出短木材。件可用。我需要的是:

  • 3 * 34"
  • 2 * 25"
  • 2 * 30"
  • 2 * 39"

到目前为止我的想法: 方法1:将最短长度设置为基础,并尝试将最长的木材长度拟合到第一个原始2by4中。只要剩余的小于最短,删除第一次计算中使用的碎片,并将所需的2by4的数量加1,重复直到使用所有碎片。 这个问题是没有办法证明这可以提供最有效的削减。可能是不同的棋子排列会完全节省2by4。

任何想法都表示赞赏。

编辑:这是我尝试用木材设计冬季轮胎架时遇到的一个真正的问题。在加拿大和美国,木材进入2" by4" by8'因此,考虑到我需要建造机架的件数和长度,我想优化我必须购买的2by4的数量。让我们把我想要的作品称为“碎片”。和2by4by8'标准'。

我上面的方法1基本上是蛮力的想法。即一个队列形成其中的碎片,然后我尽量将尽可能多的碎片装入标准中,移除使用过的'队列中的碎片,当标准中的剩余长度短于我剩下的最短片段时退出,并在我需要的标准数量上加1。这将提供一个合理有效的解决方案,并且足以满足我的目的,因为木材毕竟不是那么昂贵。考虑到这个问题让我想到了:如果木材价格昂贵,或者我在编码面试中得到这个问题怎么办,

我们如何通过数学或算法证明一种解决方案是最有效的解决方案?我正在考虑哪个部分符合剩余标准,因此没有数学证明该解决方案是最有效的。假设我们需要的部分分为长,中,短两种长度,即使我们按照从大到小的顺序对原始部件进行排序,并且在较短的部分之前开始将最长的部分装入标准中,仍然可能存在一个案例

可以使用标准

长,中,废 中,中,短,废物,
简而言之,废物 这需要3个标准,并且仅由一个短的

使用的第三个标准造成巨大浪费

而不是:
长,短,短,废物
中,中,中,废,
这需要2个标准,废物最小化。

同样,问题是,有没有办法在数学上证明解决方案或一组解决方案在最小化浪费方面最有效?

感谢到目前为止的答案,它们是我上面的蛮力解决方案。请保留证明:)

2 个答案:

答案 0 :(得分:0)

该程序使用最粗暴的蛮力解决了这个问题。它枚举第一个棒的所有可能的片段子集,然后递归,保留先前计算的缓存。有9个目标片段,只有512个子集,所以这完全足够快(因为它立即完成)。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div id="latest-ads"></div>

该程序产生此输出:

def one_stick(pieces, stick_len):
    if not pieces:
        yield (), ()
        return
    size, n = pieces[0]
    for i in xrange(n + 1):
        if size * i > stick_len:
            break
        for s, r in one_stick(pieces[1:], stick_len - size * i):
            if i < n:
                r = ((size, n - i),) + r
            if i > 0:
                s = ((size, i),) + s
            yield s, r

def sticks(pieces, stick_len, cache):
    if not pieces:
        return 0, ()
    if sum(size * n for n, size in pieces) <= stick_len:
        return 1, (pieces,)
    if pieces not in cache:
        best = 1000, []
        for s1, remainder in one_stick(pieces, stick_len):
            if not s1:
                continue
            bv, bs = sticks(remainder, stick_len, cache)
            if bv + 1 < best[0]:
                best = bv + 1, (s1,) + bs
        cache[pieces] = best
    return cache[pieces]

pieces = ((34, 3), (25, 2), (30, 2), (39, 2))
bv, bs = sticks(pieces, 8 * 12, {})
print bv
for stick in bs:
    print ' + '.join('%d*%d' % (n, size) for size, n in stick), ' \t(length = %d)' % sum(i * n for i, n in stick)

也就是说,你可以使用4件8&#39;长度。即使你不信任该程序,这也是可取的,因为你想要的长度总和是290&#34;超过3 * 8&#39;,因此找不到使用3件或更少件的解决方案是不可能的。

如果我想改进此计划,我首先要改进4 1*39 (length = 39) 1*30 + 1*39 (length = 69) 1*34 + 1*25 + 1*30 (length = 89) 2*34 + 1*25 (length = 93) 。它只能产生最大的棒子集而不是所有子集。也就是说,它会丢弃可以添加一个或多个额外棒的子集(同时保持在one_stick限制之下)。这样可以减少递归的次数,并且不会影响最优解的大小。

答案 1 :(得分:0)

我使用优秀的并行数组处理语言 Dyalog APL 粗暴地解决了这个问题。解决方案结果令人惊讶。

任务是2倍;另一方面,您希望尽量减少溢出量,但另一方面,您需要维护一个序列:

3 * 34 + 2 * 25 + 2 * 30 + 2 * 39 =一把椅子? :-)(对不起,已经写过椅子了 - 虽然看过你的编辑)

序列是一个实际问题。例如,如果是一个自雇的工匠,人们不希望提前制造大型系列。需要有一个工作的开始和结束,并且不会在现场保留大量的原材料。因此,人们希望使用几个8'的部分进行合理的“重复”,其中一个循环最终以3-2-2-2个(或多个)结束。

Paul Hankin所述,对于3个或更少的8'原料,没有解决方案。要使用的最小系列是4件,结果就是这样:

  1. 有53种独特的解决方案
  2. 每个解决方案都会产生巨大的94“泄漏(请参阅后面的评论)
  3. 这是一个惊喜(至少对我而言)。无论你如何分配长度,泄漏都稳定在94“。没有明显的方法来优化(最小化)泄漏,因为整个操作受到序列3-2-2-2的约束

    以下53种可能的解决方案。我用星号标记了其中一个,作为最佳选择,请参阅下表中的注释。

    我们使用4个8'(标记为1-4的列)。例如,最上面一行意味着我们从第一个长片切割1 * 25“,从第二个长度切割2 * 39”,2 * 34&amp;从第3个1 * 25和从第4个1 * 34“&2 * 30”。在alles,我们得到3-2-2-2件。 “溢出”列显示每个8'件的溢出量,然后是总Σ。

    ┌─────────┬─────────┬─────────┬─────────┬───────────┬──┐
    │1        │2        │3        │4        │Spills     │Σ │
    ├─────────┼─────────┼─────────┼─────────┼───────────┼──┤
    │ 0 1 0 0 │ 0 0 0 2 │ 2 1 0 0 │ 1 0 2 0 │71 18  3  2│94│
    │ 0 0 1 0 │ 1 0 0 1 │ 2 1 0 0 │ 0 1 1 1 │66 23  3  2│94│
    │ 0 0 1 0 │ 0 0 0 2 │ 1 1 1 0 │ 2 1 0 0 │66 18  7  3│94│
    │ 1 0 0 0 │ 2 0 0 0 │ 0 1 1 1 │ 0 1 1 1 │62 28  2  2│94│
    │ 1 0 0 0 │ 0 0 1 1 │ 2 1 0 0 │ 0 1 1 1 │62 27  3  2│94│
    │ 1 0 0 0 │ 1 0 0 1 │ 1 1 1 0 │ 0 1 1 1 │62 23  7  2│94│
    │ 1 0 0 0 │ 1 0 0 1 │ 0 2 0 1 │ 1 0 2 0 │62 23  7  2│94│
    │ 1 0 0 0 │ 0 0 0 2 │ 1 2 0 0 │ 1 0 2 0 │62 18 12  2│94│
    │ 1 0 0 0 │ 0 0 0 2 │ 0 1 2 0 │ 2 1 0 0 │62 18 11  3│94│
    │ 1 0 0 0 │ 0 0 0 2 │ 1 1 1 0 │ 1 1 1 0 │62 18  7  7│94│
    │ 0 0 0 1 │ 0 1 0 1 │ 2 1 0 0 │ 1 0 2 0 │57 32  3  2│94│
    │ 0 0 0 1 │ 1 0 1 0 │ 2 1 0 0 │ 0 1 1 1 │57 32  3  2│94│
    │ 0 0 0 1 │ 2 0 0 0 │ 1 1 1 0 │ 0 1 1 1 │57 28  7  2│94│
    │ 0 0 0 1 │ 2 0 0 0 │ 0 2 0 1 │ 1 0 2 0 │57 28  7  2│94│
    │ 0 0 0 1 │ 0 0 1 1 │ 1 1 1 0 │ 2 1 0 0 │57 27  7  3│94│
    │ 0 0 0 1 │ 1 0 0 1 │ 1 2 0 0 │ 1 0 2 0 │57 23 12  2│94│
    │ 0 0 0 1 │ 1 0 0 1 │ 0 1 2 0 │ 2 1 0 0 │57 23 11  3│94│
    │ 0 0 0 1 │ 1 0 0 1 │ 1 1 1 0 │ 1 1 1 0 │57 23  7  7│94│
    │ 0 2 0 0 │ 2 0 0 0 │ 0 0 0 2 │ 1 0 2 0 │46 28 18  2│94│
    │ 0 2 0 0 │ 1 0 0 1 │ 1 0 0 1 │ 1 0 2 0 │46 23 23  2│94│
    │ 0 1 1 0 │ 1 0 1 0 │ 0 0 0 2 │ 2 1 0 0 │41 32 18  3│94│ *
    │ 0 1 1 0 │ 2 0 0 0 │ 1 0 0 1 │ 0 1 1 1 │41 28 23  2│94│
    │ 0 1 1 0 │ 2 0 0 0 │ 0 0 0 2 │ 1 1 1 0 │41 28 18  7│94│
    │ 0 1 1 0 │ 0 0 1 1 │ 1 0 0 1 │ 2 1 0 0 │41 27 23  3│94│
    │ 0 1 1 0 │ 1 0 0 1 │ 1 0 0 1 │ 1 1 1 0 │41 23 23  7│94│
    │ 1 1 0 0 │ 1 1 0 0 │ 0 0 0 2 │ 1 0 2 0 │37 37 18  2│94│
    │ 1 1 0 0 │ 0 0 2 0 │ 0 0 0 2 │ 2 1 0 0 │37 36 18  3│94│
    │ 1 1 0 0 │ 0 1 0 1 │ 1 0 0 1 │ 1 0 2 0 │37 32 23  2│94│
    │ 1 1 0 0 │ 1 0 1 0 │ 1 0 0 1 │ 0 1 1 1 │37 32 23  2│94│
    │ 1 1 0 0 │ 1 0 1 0 │ 0 0 0 2 │ 1 1 1 0 │37 32 18  7│94│
    │ 1 1 0 0 │ 2 0 0 0 │ 0 0 1 1 │ 0 1 1 1 │37 28 27  2│94│
    │ 1 1 0 0 │ 2 0 0 0 │ 0 0 0 2 │ 0 1 2 0 │37 28 18 11│94│
    │ 1 1 0 0 │ 0 0 1 1 │ 0 0 1 1 │ 2 1 0 0 │37 27 27  3│94│
    │ 1 1 0 0 │ 0 0 1 1 │ 1 0 0 1 │ 1 1 1 0 │37 27 23  7│94│
    │ 1 1 0 0 │ 1 0 0 1 │ 1 0 0 1 │ 0 1 2 0 │37 23 23 11│94│
    │ 0 0 2 0 │ 0 1 0 1 │ 1 0 0 1 │ 2 1 0 0 │36 32 23  3│94│
    │ 0 0 2 0 │ 2 0 0 0 │ 1 0 0 1 │ 0 2 0 1 │36 28 23  7│94│
    │ 0 0 2 0 │ 2 0 0 0 │ 0 0 0 2 │ 1 2 0 0 │36 28 18 12│94│
    │ 0 0 2 0 │ 1 0 0 1 │ 1 0 0 1 │ 1 2 0 0 │36 23 23 12│94│
    │ 0 1 0 1 │ 0 1 0 1 │ 2 0 0 0 │ 1 0 2 0 │32 32 28  2│94│
    │ 1 0 1 0 │ 0 1 0 1 │ 2 0 0 0 │ 0 1 1 1 │32 32 28  2│94│
    │ 1 0 1 0 │ 0 1 0 1 │ 0 0 1 1 │ 2 1 0 0 │32 32 27  3│94│
    │ 1 0 1 0 │ 0 1 0 1 │ 1 0 0 1 │ 1 1 1 0 │32 32 23  7│94│
    │ 1 0 1 0 │ 1 0 1 0 │ 1 0 0 1 │ 0 2 0 1 │32 32 23  7│94│
    │ 1 0 1 0 │ 1 0 1 0 │ 0 0 0 2 │ 1 2 0 0 │32 32 18 12│94│
    │ 0 1 0 1 │ 2 0 0 0 │ 0 0 1 1 │ 1 1 1 0 │32 28 27  7│94│
    │ 1 0 1 0 │ 2 0 0 0 │ 0 0 1 1 │ 0 2 0 1 │32 28 27  7│94│
    │ 0 1 0 1 │ 2 0 0 0 │ 1 0 0 1 │ 0 1 2 0 │32 28 23 11│94│
    │ 1 0 1 0 │ 2 0 0 0 │ 0 0 0 2 │ 0 2 1 0 │32 28 18 16│94│
    │ 1 0 1 0 │ 0 0 1 1 │ 1 0 0 1 │ 1 2 0 0 │32 27 23 12│94│
    │ 1 0 1 0 │ 1 0 0 1 │ 1 0 0 1 │ 0 2 1 0 │32 23 23 16│94│
    │ 2 0 0 0 │ 0 0 1 1 │ 0 0 1 1 │ 1 2 0 0 │28 27 27 12│94│
    │ 2 0 0 0 │ 0 0 1 1 │ 1 0 0 1 │ 0 2 1 0 │28 27 23 16│94│
    └─────────┴─────────┴─────────┴─────────┴───────────┴──┘
    

    标有星的行显然是最佳的,因为它包含两个长的休息片,41“和32”。这两个允许任何两个短长度,这意味着对于每把椅子(= 9件),你会得到 2/9椅子: - )。或者反过来,对于每4.5个椅子,你会得到一把额外的椅子! Otoh,它也给这个问题带来了全新的麻烦:一些解决方案“泄漏”了可用的原材料,应该在未来的周期中处理。哪些泄漏符合什么,什么时候应该被消费,...等等: - )。

    由于我有这个小APL代码片段方便,我也试过其他原料长度。一些发现:

    2件长件

    原来最小材料长度约为12.17'。我们得到了下面的结果,更长的原材料似乎没有改善任何东西,因为我们只是每个椅子消耗2 * 12.17'(但是我们得到更多“泄漏”的材料,甚至更长的长度)。

    ┌─────────┬─────────┬─────────┬────┐
    │1        │2        │Spills   │Σ   │
    ├─────────┼─────────┼─────────┼────┤
    │ 1 2 2 0 │ 2 0 0 2 │2.04 0.04│2.08│
    └─────────┴─────────┴─────────┴────┘
    

    3件长

    如果你可以将原材料只用0.17'扩展到8.17',那么你就会得到一个相当不错的分割:

    ┌─────────┬─────────┬─────────┬──────────────┬────┐
    │1        │2        │3        │Spills        │Σ   │
    ├─────────┼─────────┼─────────┼──────────────┼────┤
    │ 0 1 1 1 │ 2 0 1 0 │ 1 1 0 1 │4.04 0.04 0.04│4.12│
    │ 1 0 2 0 │ 1 1 0 1 │ 1 1 0 1 │4.04 0.04 0.04│4.12│
    └─────────┴─────────┴─────────┴──────────────┴────┘
    

    增加原料长度会增加漏油量。 9.5'给出了32个唯一的第一行:

    ┌─────────┬─────────┬─────────┬────────┬──┐
    │1        │2        │3        │Spills  │Σ │
    ├─────────┼─────────┼─────────┼────────┼──┤
    │ 1 0 1 0 │ 1 0 0 2 │ 1 2 1 0 │50  2  0│52│
    │ 2 0 0 0 │ 0 0 1 2 │ 1 2 1 0 │46  6  0│52│
    │ 2 0 0 0 │ 0 2 2 0 │ 1 0 0 2 │46  4  2│52│
    │ 0 0 1 1 │ 2 0 0 1 │ 1 2 1 0 │45  7  0│52│
    │ 1 0 0 1 │ 1 0 1 1 │ 1 2 1 0 │41 11  0│52│
    │ 1 0 0 1 │ 2 0 0 1 │ 0 2 2 0 │41  7  4│52│
    

    4件长

    事实证明,如果我们有短至6.67',我们得到:

    ┌─────────┬─────────┬─────────┬─────────┬─────────────────────┬─────┐
    │1        │2        │3        │4        │Spills               │Σ    │
    ├─────────┼─────────┼─────────┼─────────┼─────────────────────┼─────┤
    │ 1 0 1 0 │ 2 0 0 0 │ 0 0 0 2 │ 0 2 1 0 │16.04 12.04 2.04 0.04│30.16│
    │ 1 0 1 0 │ 1 0 0 1 │ 1 0 0 1 │ 0 2 1 0 │16.04  7.04 7.04 0.04│30.16│
    │ 2 0 0 0 │ 0 0 1 1 │ 1 0 0 1 │ 0 2 1 0 │12.04 11.04 7.04 0.04│30.16│
    └─────────┴─────────┴─────────┴─────────┴─────────────────────┴─────┘
    

    这似乎是4个周期的最小值。

    7'我们得到:

    ┌─────────┬─────────┬─────────┬─────────┬──────────┬──┐
    │1        │2        │3        │4        │Spills    │Σ │
    ├─────────┼─────────┼─────────┼─────────┼──────────┼──┤
    │ 0 0 2 0 │ 2 0 0 0 │ 0 0 0 2 │ 1 2 0 0 │24 16  6 0│46│
    │ 0 0 2 0 │ 1 0 0 1 │ 1 0 0 1 │ 1 2 0 0 │24 11 11 0│46│
    │ 1 0 1 0 │ 1 0 1 0 │ 0 0 0 2 │ 1 2 0 0 │20 20  6 0│46│
    │ 1 0 1 0 │ 2 0 0 0 │ 0 0 0 2 │ 0 2 1 0 │20 16  6 4│46│
    │ 1 0 1 0 │ 0 0 1 1 │ 1 0 0 1 │ 1 2 0 0 │20 15 11 0│46│
    │ 1 0 1 0 │ 1 0 0 1 │ 1 0 0 1 │ 0 2 1 0 │20 11 11 4│46│
    │ 2 0 0 0 │ 0 0 1 1 │ 0 0 1 1 │ 1 2 0 0 │16 15 15 0│46│
    │ 2 0 0 0 │ 0 0 1 1 │ 1 0 0 1 │ 0 2 1 0 │16 15 11 4│46│
    └─────────┴─────────┴─────────┴─────────┴──────────┴──┘
    

    7.5':

    ┌─────────┬─────────┬─────────┬─────────┬───────────┬──┐
    │1        │2        │3        │4        │Spills     │Σ │
    ├─────────┼─────────┼─────────┼─────────┼───────────┼──┤
    │ 1 0 0 0 │ 0 0 0 2 │ 1 1 1 0 │ 1 1 1 0 │56 12  1  1│70│
    │ 0 0 0 1 │ 1 0 0 1 │ 1 1 1 0 │ 1 1 1 0 │51 17  1  1│70│
    │ 0 1 1 0 │ 2 0 0 0 │ 0 0 0 2 │ 1 1 1 0 │35 22 12  1│70│
    │ 0 1 1 0 │ 1 0 0 1 │ 1 0 0 1 │ 1 1 1 0 │35 17 17  1│70│
    │ 1 1 0 0 │ 1 0 1 0 │ 0 0 0 2 │ 1 1 1 0 │31 26 12  1│70│
    (ca 20 more rows)
    

    9'给出229个唯一身份:

    ┌─────────┬─────────┬─────────┬─────────┬────────────┬───┐
    │1        │2        │3        │4        │Spills      │Σ  │
    ├─────────┼─────────┼─────────┼─────────┼────────────┼───┤
    │ 0 0 0 0 │ 0 2 1 0 │ 3 0 0 0 │ 0 0 1 2 │108 28  6  0│ 34│ <- Note, this is a 3-cycle result
    │ 0 0 0 0 │ 0 2 1 0 │ 1 0 1 1 │ 2 0 0 1 │108 28  5  1│ 34│ <- Ditto
    │ 0 0 0 0 │ 1 2 0 0 │ 2 0 1 0 │ 0 0 1 2 │108 24 10  0│ 34│ <- Ditto
     (scrapped rows)
    │ 2 0 0 0 │ 0 0 1 1 │ 0 0 1 1 │ 1 2 0 0 │ 40 39 39 24│142│ *
    │ 2 0 0 0 │ 0 0 1 1 │ 1 0 0 1 │ 0 2 1 0 │ 40 39 35 28│142│ *
    └─────────┴─────────┴─────────┴─────────┴────────────┴───┘
    

    进一步的4周期结果似乎会增加泄漏(并产生更多“泄漏”)

    结论

    忽略上述实验长度并关注原始参数,3个长片循环的最佳解决方案似乎是

    ┌─────────┬─────────┬─────────┬─────────┬───────────┬──┐
    │1        │2        │3        │4        │Spills     │Σ │
    ├─────────┼─────────┼─────────┼─────────┼───────────┼──┤
    │ 0 1 1 0 │ 1 0 1 0 │ 0 0 0 2 │ 2 1 0 0 │41 32 18  3│94│ *
    

    因为我们可以进一步使用泄露的材料。但是,我们有可能开始关注原始序列3-2-2-2的倍数以及更高的周期长度。我不知道接下来会发生什么:-)。这可能是永无止境的情况

    “泄露的材料”使这成为一种递归的东西,至少在没有进一步约束的情况下,这种感觉几乎无法解决。什么时候重新使用?在3个循环中,在22个循环中?你有多少套“泄漏的材料”同时使用,按照它的顺序使用它?呵呵......你有一辈子要用吗?

    对于各种小长度组合,可能有可能解决“最小长度” - 最小溢出的断点。

    (对不起,我没有提供任何代码,但如果您想调查该区域,我会有一个快速而又脏的APL功能。)

    尝试获得8.17'原材料,你会节省很多!! (参见“3长片”标题)。