Я пишу какую-то викторину, и мне нужен компьютер, чтобы решить 1 игру в викторине, если игроки не смогут ее решить.
Даны данные:
- Список из 6 чисел для использования, например 4, 8, 6, 2, 15, 50.
- Целевое значение, где 0 ‹ значение ‹ 1000, например 590.
- Доступные операции: деление, сложение, умножение и деление.
- Можно использовать скобки.
Сгенерируйте математическое выражение, оценка которого равна или максимально близка к целевому значению. Например, для приведенных выше чисел выражение может быть таким: (6 + 4) * 50 + 15 * (8 - 2) = 590.
Мой алгоритм следующий:
- Сгенерируйте все перестановки всех подмножеств заданных чисел из (1) выше
- Для каждой перестановки сгенерируйте все комбинации скобок и операторов
- Отслеживание ближайшего значения по мере выполнения алгоритма
Я не могу придумать какой-либо умной оптимизации алгоритма перебора выше, который ускорит его на порядок. Также я должен оптимизировать для наихудшего случая, потому что на сервере одновременно будет запущено много игр-викторин.
Код, написанный сегодня для решения этой проблемы (соответствующие материалы, извлеченные из проекта):
from operator import add, sub, mul, div
import itertools
ops = ['+', '-', '/', '*']
op_map = {'+': add, '-': sub, '/': div, '*': mul}
# iterate over 1 permutation and generates parentheses and operator combinations
def iter_combinations(seq):
if len(seq) == 1:
yield seq[0], str(seq[0])
else:
for i in range(len(seq)):
left, right = seq[:i], seq[i:] # split input list at i`th place
# generate cartesian product
for l, l_str in iter_combinations(left):
for r, r_str in iter_combinations(right):
for op in ops:
if op_map[op] is div and r == 0: # cant divide by zero
continue
else:
yield op_map[op](float(l), r), \
('(' + l_str + op + r_str + ')')
numbers = [4, 8, 6, 2, 15, 50]
target = best_value = 590
best_item = None
for i in range(len(numbers)):
for current in itertools.permutations(numbers, i+1): # generate perms
for value, item in iter_combinations(list(current)):
if value < 0:
continue
if abs(target - value) < best_value:
best_value = abs(target - value)
best_item = item
print best_item
Он печатает: ((((4*6)+50)*8)-2). Немного протестировал его с разными значениями, и, похоже, он работает правильно. Также у меня есть функция удаления ненужных скобок, но она не имеет отношения к вопросу, поэтому не публикуется.
Проблема в том, что это работает очень медленно из-за всех этих перестановок, комбинаций и оценок. На моем Mac Book Air он работает в течение нескольких минут для 1 примера. Я хотел бы, чтобы он запускался максимум за несколько секунд на одном компьютере, потому что на сервере одновременно будет запускаться множество экземпляров игры-викторины. Итак, вопросы:
- Можно ли как-то (на порядки) ускорить текущий алгоритм?
- Я пропустил какой-то другой алгоритм для этой проблемы, который будет работать намного быстрее?
<number> { <operation> <number> }+
, который может быть проанализирован до результата<number>
, учитывая, что операции ограничены 4, разбор слева направо и числа не используются повторно. Полный линейный алгоритм, безусловно, существует, поскольку существует Это конечное число возможных комбинаций - person Khaled.K   schedule 19.12.2013division, addition,
division,
multiplication and division
? О, подождите,op_map
включает'-': sub
. - person greybeard   schedule 08.03.2019