使用预定义值填充一维空间

时间:2017-02-12 19:04:52

标签: python c algorithm

我想用预定义的" subLengths"来填充长度。 比方说我的subLength是:3,4,5,6,7,10。 要填写15的长度,我可以使用" 10 + 5" ," 3 + 4 + 3 + 5" " 7 + 4 + 4" " 7 + 5 + 3" .... 我怎么能得到这些结果中的一个数组呢? 更好:我怎么能得到一个数组好几个好结果?我的最大长度是70,我想要获得这个值的所有好结果可能会很费时间。

我是一名3D艺术家,我的编码技巧很有限,我只是不知道如何处理这个问题。我可以使用Python或类似C的语言。

此代码似乎适用于我的软件:

def fillBuild(length, subLengths):

    for i in range(len(subLengths)):        
            if subLengths[i] == length:
                    yield subLengths[i:i + 1]
            elif subLengths[i] < length:
                    for subResult in fillBuild(length - subLengths[i] ,subLengths[i:] ):
                            yield subLengths[i:i + 1] + subResult

2 个答案:

答案 0 :(得分:0)

这是一个使用Python 2.7的递归解决方案:

def fill(length, sublengths):
    # IMPORTANT: this function will produce INCORRECT RESULTS if sublengths
    # is not a list of unique integers sorted increasingly.

    fillings = []

    for i, sublength in enumerate(sublengths):

        if sublength > length:
            # if sublength is greater than length, there are no more allowable
            # fillings (because sublengths are unique and are sorted
            # increasingly), so we return the fillings collected so far;
            return fillings

        elif sublength == length:
            # if sublength is exactly equal to length, then only one filling is
            # possible, namely [sublength]; we append this filling to the
            # fillings;
            fillings.append([sublength])

       else:
            # we generate all the fillings that begin with sublength by
            # prepending sublength to all the allowable fillings of
            # (length - sublength), which we obtain by making a recursive call.
            fillings.extend([[sublength] + subresult
                             for subresult in
                             fill(length - sublength, sublengths[i:])])

示例:

In [2]: fill(15, [3, 4, 5, 6, 7, 10])
Out[2]: 
[[3, 3, 3, 3, 3],
 [3, 3, 3, 6],
 [3, 3, 4, 5],
 [3, 4, 4, 4],
 [3, 5, 7],
 [3, 6, 6],
 [4, 4, 7],
 [4, 5, 6],
 [5, 5, 5],
 [5, 10]]
BTW:fill(70, [3, 4, 5, 6, 7, 10]))产生了1657种可能的填充物,因此您可能需要一些额外的标准来减少替代品。

一些注意事项:

  • 为了避免重复解决方案,我们将要求逐步订购每个灌装;

  • 关键思想是:假设要填充的长度是 L ,而 a 1 &lt; a 2 &lt; ......&lt; a n 是可用的sublengths。要找到以 1 开头的 L 的所有可能填充,等于预先 a 1 L 的所有填充 - a 1 。这是else fill块中递归调用的基本原理。 (当函数调用自身时,如fill所做的那样,该函数被称为递归。)

  • 由于fill要求sublengths没有重复项并且排序越来越多,我们可以使用以下前端函数来确保满足这些条件:

    def do_fill(长度,sublengths):     返回填充(长度,排序(设置(sublengths)))

NB:下面是对代码执行操作的相当详细的解释。如果您已经理解了代码,则可以安全地跳过本文的其余部分。)

为了更好地了解正在发生的事情,请回到上面的示例,然后根据第一个问题对解决方案进行分组。你会得到以下三组:

 # group I
 [3, 3, 3, 3, 3]
 [3, 3, 3, 6]
 [3, 3, 4, 5]
 [3, 4, 4, 4]
 [3, 5, 7]
 [3, 6, 6]

 # group II
 [4, 4, 7]
 [4, 5, 6]

 # group III
 [5, 5, 5]
 [5, 10]

现在,使用sublengths [3,4,5,6,7,10]比较组I中的填充物,其中所有填充物均以3开头,填充物为15-3 = 12:

In [3]: fill(15 - 3, [3, 4, 5, 6, 7, 10])
Out[3]: 
[[3, 3, 3, 3],
[3, 3, 6],
[3, 4, 5],
[4, 4, 4],
[5, 7],
[6, 6]]

如果现在你在所有这些填充物前面加3,你就可以得到第I组的填充物。

现在考虑组II中的填充物,所有填充物都以4开始。使用sublengths [4,5,6,7,10]将它们与15-4 = 11的填充物进行比较:

In [4]: fill(15 - 4, [4, 5, 6, 7, 10])
Out[4]: 
[4, 7],
[5, 6]

同样,如果你在所有这些填充物前面加4,你就可以得到第II组中的填充物。

您可能想知道,为什么我使用[4,5,6,7,10]作为上次fill的最后一次调用的次要长度,而不是[3,4,5,6,7, 10]?这是因为我只对那些越来越有序且以4开头的填充物感兴趣。这排除了任何包含3的填充物。

最后,为了获得第III组的填充物,使用sublengths [5,6,7,10],将所有填充物的前置5分为15 - 5 = 10:

In [5]: fill(15 - 5, [5, 6, 7, 10])
Out[5]: 
[[5, 5],
[10]]

如果您如此倾向,可以对每个子组重复相同的分析。例如,您可以根据他们的第一个元素对fill(15 - 3, [3, 4, 5, 6, 7, 10])生成的填充进行分组;你会得到4组:

[3, 3, 3, 3]
[3, 3, 6]
[3, 4, 5]

[4, 4, 4]

[5, 7]

[6, 6]

这些组分别通过将3,4,5或6分别添加到

生成的填充物中获得。
fill((15 - 3) - 3, [3, 4, 5, 6, 7, 10])
fill((15 - 3) - 4, [   4, 5, 6, 7, 10])
fill((15 - 3) - 5, [      5, 6, 7, 10])
fill((15 - 3) - 6, [         6, 7, 10])

上面的分析只是“手动”完成了fill函数的作用。

需要注意的一点是,每次递归调用时,问题都会变得更简单。

例如,在生成填充[3,5,7]的过程中,对fill的以下调用已执行:

fill(15,         [3, 4, 5, 6, 7, 10]) = fill(15, [3, 4, 5, 6, 7, 10])
fill(15 - 3,     [3, 4, 5, 6, 7, 10]) = fill(12, [3, 4, 5, 6, 7, 10])
fill(15 - 3 - 5, [      5, 6, 7, 10]) = fill( 7, [      5, 6, 7, 10])

请特别注意最后一个fill(7, [5, 6, 7, 10])。人们可以通过检查发现它的解决方案:只有一次填充7可以从子长度[5,6,7,10]。递归总是以这些微不足道的案例的解决方案结束。最终的解决方案来自这些微不足道的解决方案。

答案 1 :(得分:0)

递归生成器函数(Python)生成pool加起来total的所有可能的子列表排列(重复):

from pprint import pprint

def sub_lists(pool, total):
    for i in range(len(pool)):
        if pool[i] == total:
            yield pool[i:i + 1]
        elif pool[i] < total:
            for sub_list in sub_lists(pool, total - pool[i]):
                yield pool[i:i + 1] + sub_list

pprint(list(sub_lists([3, 4, 5, 6, 7, 10], 15)))
[[3, 3, 3, 3, 3],
 [3, 3, 3, 6],
 [3, 3, 4, 5],
 [3, 3, 5, 4],
 [3, 3, 6, 3],
 [3, 4, 3, 5],
 [3, 4, 4, 4],
 [3, 4, 5, 3],
 [3, 5, 3, 4],
 [3, 5, 4, 3],
 [3, 5, 7],
 [3, 6, 3, 3],
 [3, 6, 6],
 [3, 7, 5],
 [4, 3, 3, 5],
 [4, 3, 4, 4],
 [4, 3, 5, 3],
 [4, 4, 3, 4],
 [4, 4, 4, 3],
 [4, 4, 7],
 [4, 5, 3, 3],
 [4, 5, 6],
 [4, 6, 5],
 [4, 7, 4],
 [5, 3, 3, 4],
 [5, 3, 4, 3],
 [5, 3, 7],
 [5, 4, 3, 3],
 [5, 4, 6],
 [5, 5, 5],
 [5, 6, 4],
 [5, 7, 3],
 [5, 10],
 [6, 3, 3, 3],
 [6, 3, 6],
 [6, 4, 5],
 [6, 5, 4],
 [6, 6, 3],
 [7, 3, 5],
 [7, 4, 4],
 [7, 5, 3],
 [10, 5]]