如何蛮力算术拼图?

时间:2015-03-30 18:19:13

标签: algorithm math

一位朋友分享了这个难题:

  

如何从数字1,5,6,7中制作21?

     

您可以使用加法,减法,乘法和除法以及括号的操作。您必须使用每个号码一次。

两天后我终于在纸上解决了这个问题。毫无疑问,计算机可以在一秒钟内强制执行所有解决方案。

怎么样?我尝试生成所有字符串a.b.c.d插入字母的数字和点的操作,但它错过了我的解决方案。


奖金谜题:

  • 如何从1,5,6,7生成11?
  • 如何从1,5,6,7制作16?

2 个答案:

答案 0 :(得分:9)

一个明显的方法是:

  1. 您从一个包含四个数字的S矢量开始:S = ( 1, 5, 6, 7 )
  2. a中挑选任意两个号码bS,将其从S
  3. 中删除
  4. ab应用任意算术运算,从而获得一个新的数字c(如果问题需要,请注意避免除零并验证精确除法)
  5. c加入S,从而获得S'
  6. 从第1步继续,现在使用S'代替S
  7. 在步骤2(选择两个数字)和步骤3(选择操作)执行强力分支。应该重复该循环,直到S减少到只有1个元素,这是这个特定的强力分支的结果。

    未明确使用括号,但它们是隐式存在的。

    如果一个分支以21中的S结尾,则您有一个解决方案,此时您可以终止或继续分支以搜索其他解决方案。

答案 1 :(得分:2)

在这里"弹出两个,结合,递归" AnT建议的算法,用Python编码。最难的部分是在递归后组装表达式。我使用了find-and-replace。

#!python
import operator
import itertools
from fractions import Fraction

operations = dict()
operations['+'] = operator.add
operations['-'] = operator.sub
operations['/'] = operator.truediv
operations['*'] = operator.mul

def solve(target, numbers):
    """List ways to make target from numbers."""
    numbers = [Fraction(x) for x in numbers]
    return solve_inner(target, numbers)

def solve_inner(target, numbers):
    if len(numbers) == 1:
        if numbers[0] == target:
            yield str(target)
        return

    # combine a pair of numbers with an operation, then recurse
    for a,b in itertools.permutations(numbers, 2):
        for symbol, operation in operations.items():
            try:
                product = operation(a,b)
            except ZeroDivisionError:
                continue

            subnumbers = list(numbers)
            subnumbers.remove(a)
            subnumbers.remove(b)
            subnumbers.append(product)

            for solution in solve_inner(target, subnumbers):
                # expand product (but only once)
                yield solution.replace(str(product), "({0}{1}{2})".format(a, symbol, b), 1)

if __name__ == "__main__":
    numbers = [1, 5, 6, 7]
    target = 21
    solutions = solve(target, numbers)
    for solution in solutions:
        print("{0}={1}".format(target, solution))

三个谜题的解决方案:

>>> solve(21,[1,5,6,7])
6/(1-(5/7))
>>> solve(11,[1,5,6,7])
(6*(7-5))-1
((7-5)*6)-1
>>> solve(16,[1,5,6,7])
[]

(第三个难题是不可能的)