使用乘法获得整数唯一组合的算法

时间:2010-11-12 18:52:37

标签: algorithm combinations

我得到一堆2s和3s,我必须在一起。现在我想生成这些数字的每个唯一组合,以便当这些组合相乘时不超过10。

例如,我有类似的东西。

2*2*2*2*3*3*3

我可以从上面获得以下有效组合。

4*4*9*3
8*6*9
4*2*6*9

但以下组合是错误的。 16*3*94*4*27

有人建议使用算法吗?

2 个答案:

答案 0 :(得分:2)

可以递归地构建解决方案。将输入视为数字列表,例如[2,2,2,2,3,3,3]。将列表分为前缀(例如[2,2])和相应的后缀(在这种情况下为[2,2,3,3,3])。现在多个前缀中的条目(在本例中我们得到4),并递归地解决了后缀的相同问题。将多重性的值插入到后缀的每个解的开头,我们得到原始问题的答案。

在下面的Python代码中,递归逻辑在函数collapse中定义,它找到所有有效前缀(其多重性小于10)并将多重性插入到折叠剩余数据时返回的所有结果中在删除前缀(collapse(d[prefix_len:]))之后。

a = [2,2,2,2,3,3,3]

def collapse(d):
    if len(d) > 0:
        for prefix_len in range(1, len(d) + 1):
            prefix = reduce(lambda x,y: x*y, d[:prefix_len], 1)
            if prefix > 10:
                break
            for suffix in collapse(d[prefix_len:]):
                yield [prefix] + suffix
    else:
        yield d

for i in collapse(a):
    print i

输出

[2, 2, 2, 2, 3, 3, 3]
[2, 2, 2, 2, 3, 9]
[2, 2, 2, 2, 9, 3]
[2, 2, 2, 6, 3, 3]
[2, 2, 2, 6, 9]
[2, 2, 4, 3, 3, 3]
[2, 2, 4, 3, 9]
[2, 2, 4, 9, 3]
[2, 4, 2, 3, 3, 3]
[2, 4, 2, 3, 9]
[2, 4, 2, 9, 3]
[2, 4, 6, 3, 3]
[2, 4, 6, 9]
[2, 8, 3, 3, 3]
[2, 8, 3, 9]
[2, 8, 9, 3]
[4, 2, 2, 3, 3, 3]
[4, 2, 2, 3, 9]
[4, 2, 2, 9, 3]
[4, 2, 6, 3, 3]
[4, 2, 6, 9]
[4, 4, 3, 3, 3]
[4, 4, 3, 9]
[4, 4, 9, 3]
[8, 2, 3, 3, 3]
[8, 2, 3, 9]
[8, 2, 9, 3]
[8, 6, 3, 3]
[8, 6, 9]

答案 1 :(得分:2)

如果订单很重要(即2 * 4 * 2与2 * 2 * 4不同)并且您必须列出它们(即“生成”),那么您应该以递归方式完成所有操作。在斯卡拉:

def combine(who: List[Int], limit: Int=10): List[List[Int]] = who match {
  case x :: y :: more =>
    combine(y :: more, limit).map(x :: _) :::
    (if (x*y<limit) combine((x*y) :: more, limit) else Nil)
  case x :: Nil => List(who)
  case Nil => List()
}

你可能不知道Scala,所以这里有三种情况。第一种情况:列表至少剩下两个元素。选择第一个元素并将其添加到所有可能的后续组合中。然后, if 可以合并第一个和第二个元素,这样做,并找到以该开头的列表的所有组合。第二种情况:只有一个元素的简单列表;将其作为列表中的唯一内容返回。第三种情况:退化输入(没有给出值);返回一个空列表。

(在Scala中,:::将两个列表连接在一起,而x :: listx粘贴在list的前面。当您匹配时,它会反过来周围:如果列表可以分解为元素case x :: stuff,则使用x,其余的stuffNil是空列表。)

这是在行动:

scala> combine( List(2,2,2,2,3,3,3) )

res18: List[List[Int]] = List(List(2, 2, 2, 2, 3, 3, 3), List(2, 2, 2, 2, 3, 9),
  List(2, 2, 2, 2, 9, 3), List(2, 2, 2, 6, 3, 3), List(2, 2, 2, 6, 9),
  List(2, 2, 4, 3, 3, 3), List(2, 2, 4, 3, 9), List(2, 2, 4, 9, 3),
  List(2, 4, 2, 3, 3, 3), List(2, 4, 2, 3, 9), List(2, 4, 2, 9, 3), List(2, 4, 6, 3, 3),
  List(2, 4, 6, 9), List(2, 8, 3, 3, 3), List(2, 8, 3, 9), List(2, 8, 9, 3),
  List(4, 2, 2, 3, 3, 3), List(4, 2, 2, 3, 9), List(4, 2, 2, 9, 3), List(4, 2, 6, 3, 3),
  List(4, 2, 6, 9), List(4, 4, 3, 3, 3), List(4, 4, 3, 9), List(4, 4, 9, 3),
  List(8, 2, 3, 3, 3), List(8, 2, 3, 9), List(8, 2, 9, 3), List(8, 6, 3, 3), List(8, 6, 9))

编辑:如果您只想计算它们,则会使用不同类型的重复。让S(n)为从n开始的组合数,让L(n)为列表中n项的值。然后

S(i) = S(i+1) +
       if (L(i)+L(i+1)<10) S(i+2) +
       if (L(i)+...+L(i+2)<10) S(i+3) +
       ....

所以你从最后一项开始 - 只有一种可能性 - 然后使用这个公式按顺序向后工作。 (如果这是你所追求的,我会编写代码,但希望算法足够清晰。)