Classical task: you have numbers 1,5,6,7
and operations (),+,-,*,/,^
. You have to build arithmetical expression which result will be 21
(without repeats!). For searching is solutions tree we'll use backtracking, for arithmetics - stack machine, like Forth. Search extracts element of each level with extract_e()
from rest of variants cases
, all other ones will be searching recursively. Function goal()
is the predicate, which determines do we need to add found path into solutions list found
. It has empiric: must be more than 1 numbers on the stack!
from functools import *
# split seq by element index, returns element and all other elements
extract_e = lambda seq, i: (seq[i], seq[:i] + seq[i+1:])
# all indexes of sequence
indexes = lambda seq: range(len(seq))
# backtracking
def bt(cases, goal, found=[], level=0, path=[]):
if goal(path, level): found.append(path)
for i in indexes(cases):
c, rest = extract_e(cases, i)
bt(rest, goal, found, level+1, path + [c])
if 0 == level: return found
# Solver - uses postfix arithm.
class Solver:
VALUES, OPERATORS = (1,5,6,7), ('+', '-', '*', '/', '^')
@staticmethod
def _binop(stack, op_ch):
ops = { "+": lambda a, b: b+a, "-": lambda a, b: b-a,
"*": lambda a, b: b*a, "/": lambda a, b: b/a,
"^": lambda a, b: b**a, }
stack.append(ops[op_ch](stack.pop(), stack.pop()))
def eval(self, state, default=None):
try:
stack = []
for c in state:
if c in self.VALUES: stack.append(int(c))
else: self._binop(stack, c)
return stack.pop()
except:
return default
def __call__(self):
def goal(path, level):
if len(path) > 2 and all(e in self.VALUES for e in path[:2]):
try: return 21 == int(self.eval(path))
except: return
return bt(self.VALUES + self.OPERATORS, goal)
print("Found:", Solver()())
The same BT-search may be used for sorting:
# predicate: is seq ordered?
ordered = lambda seq: reduce(lambda i,e: (i[0] and e>=i[1], e), seq, (1, seq[0]))[0]
seq = [9,1,5,4]
print("In:", seq)
def completed(path, level): return level==len(seq) \
and ordered(path)
print(bt(seq, completed))
Комментариев нет:
Отправить комментарий
Thanks for your posting!