﻿ python – 在分配和交换法则下查找等效结果 - 代码日志

#### python – 在分配和交换法则下查找等效结果

``````312 / 130 x 350 - 122 + 282 = 1000.0
312 / 130 x 350 + 282 - 122 = 1000.0
312 - 282 x 372 / 15 + 256 = 1000.0
142 + 350 - 372 x 125 / 15 = 1000.0
142 + 350 - 372 / 15 x 125 = 1000.0
350 / 130 x 312 + 282 - 122 = 1000.0
350 + 142 - 372 x 125 / 15 = 1000.0
``````

``````312 / 130 x 350 - 122 + 282 = 1000.0
312 - 282 x 372 / 15 + 256 = 1000.0
142 + 350 - 372 x 125 / 15 = 1000.0
``````

``````142 + 350 - 372 x 125 / 15 = 1000.0
``````

``````(((142 + 350) - 372) x 125) / 15 = 1000.0
``````

``````import operator
from itertools import permutations, product, count
from functools import reduce

vectors = [[87, 125, 209, 312],
[29, 122, 254, 372],
[15, 130, 277, 369],
[142, 197, 282, 383],
[64, 157, 256, 350]]

OPER = {operator.add: '+', operator.sub: '-', operator.mul: 'x',
operator.truediv: '/'}

def format_result(nums, ops, res):
s = ' '.join('{} {}'.format(n,OPER[op]) for n,op in zip(nums, ops))
s += ' {} = {}'.format(nums[-1], res)
return s

def calc(vectors, test=lambda x: x == 1000.):
for vv in permutations(vectors):
for indexes in product((0,1,2,3), repeat=5):
numbers = tuple(v[i] for i,v in zip(indexes, vv))
for operations in permutations(OPER):
res = reduce(lambda x,y,n=count(0): operations[next(n)](x,y),
numbers)
if test(res):
print(format_result(numbers, operations, res))

calc(vectors)
``````

``````312 / 130 x 350 + 122 + 282   => (/, [312, 130]), (x, [350]), (+, [122, 282])
``````

> – 组不能直接在组之前发生
> / groups不能直接在*组之前发生
>在每个组中,数字的顺序必须是升序

>“前3个asc.操作数连接a,然后2个asc.操作数连接a *”
>“第一个asc.操作数连接a,然后2个asc.操作数连接一个*,然后2个asc.操作数连接到/”

>“前2个asc.操作数连接 – ,然后3个asc.操作数连接”(将与“前3个asc.操作数连接a,然后2个asc.操作数连接 – ”

``````import operator
import fractions
from itertools import permutations, product, count
from functools import reduce

vectors = [[87, 125, 209, 312],
[29, 122, 254, 372],
[15, 130, 277, 369],
[142, 197, 282, 383],
[64, 157, 256, 350]]
vectors = [[fractions.Fraction(x) for x in v] for v in vectors]

operators = {
'-': operator.sub,
'*': operator.mul,
'/': operator.div,
}

def create_groupings(n, exclude = ()):
if n <= 0: yield ()
for i in range(1, n+1):
if not '+' in exclude:
for rest in create_groupings(n - i, ('+',)):
yield ((i, '+'),) + rest
if not '-' in exclude:
for rest in create_groupings(n - i, ('+', '-')):
yield ((i, '-'),) + rest
if not '*' in exclude:
for rest in create_groupings(n - i, ('*',)):
yield ((i, '*'),) + rest
if not '/' in exclude:
for rest in create_groupings(n - i, ('/', '*')):
yield ((i, '/'),) + rest

def fill_grouping(groups, vectors):
if len(groups) == 0:
yield ()
return

(group_size, op), grest = groups[0], groups[1:]
for vv in permutations(vectors):
vecs, vrest = vectors[:group_size], vectors[group_size:]
for operands in map(list, product(*vecs)):
# enforce ascending ordering to avoid collisions
# like A + B == B + A
if operands != sorted(operands): continue
for rest in fill_grouping(grest, vrest):
yield ((op, operands),) + rest

groupings = create_groupings(5)
for g in groupings:
for groups in fill_grouping(g, vectors):
evaluated = ((op, reduce(operators[op], x)) for (op, x) in groups)
_, value = reduce(lambda (_, x), (op, y): (None, operators[op](x,y)), evaluated)
if 1000 == value:
print groups
``````