Створіть число, використовуючи заданий список чисел та арифметичні оператори


11

Вам надають список номерів L = [17, 5, 9, 17, 59, 14], мішок операторів O = {+:7, -:3, *:5, /:1}та номер N = 569.

Завдання

Виведіть рівняння, яке використовує всі числа в Lлівій частині і лише число Nна правій частині. Якщо це неможливо, виведіть помилково. Приклад рішення:

59*(17-5)-9*17+14 = 569

Обмеження та уточнення

  • Ви не можете об'єднати числа ( [13,37]не можна використовувати як 1337)
  • У ньому відображатимуться лише натуральні числа та нуль L.
  • Порядок Lне має значення.
  • Ви повинні використовувати всі номери в L.
  • Тільки оператори +, -, *, /з'являться O.
  • Oможе мати більше операторів, ніж потрібно, але принаймні |L|-1операторів
  • Ви можете використовувати кожного оператора будь-яку кількість разів до значення в O.
  • Усі чотири операції в O- це стандартні математичні операції; зокрема, /це нормальний поділ на точні дроби.

Очки

  • Чим менше очок, тим краще
  • Кожен символ вашого коду дає вам один бал

Ви повинні надати версію без гольфу, яку легко читати.

Фон

Аналогічне питання було поставлено питання про переповнення стека. Я подумав, що це може бути цікавим завданням з коду-гольфу.

Комп'ютерна складність

Як сказав Пітер Тейлор у коментарях, ви можете вирішити суму підмножини за допомогою цього:

  1. У вас є екземпляр суми підмножини (звідси набір S цілих чисел і число x)
  2. L: = S + [0, ..., 0] (| S | разів нуль), N: = x, O: = {+: | S | -1, *: | S | - 1, /: 0, -: 0}
  3. Тепер вирішіть цей приклад моєї проблеми
  4. Рішення для сукупності підмножини - це числа S, які не перемножуються на нуль.

Якщо ви знайдете алгоритм, кращий за O (2 ^ n), ви докажете, що P = NP. Оскільки P vs NP - проблема премії тисячоліття і, отже, коштує 1 000 000 доларів США, то малоймовірно, що хтось знайде рішення для цього. Тому я зняв цю частину рейтингу.

Тестові справи

Нижче наведено не єдино вагомі відповіді, інші рішення існують і дозволені:

  • ( [17,5,9,17,59,14], {+:7, -:3, *:5, /:1}, 569)
    => 59 * (17-5)- 9 * 17 + 14 = 569
  • ( [2,2], {'+':3, '-':3, '*':3, '/':3}, 1)
    => 2/2 = 1
  • ( [2,3,5,7,10,0,0,0,0,0,0,0], {'+':20, '-':20, '*':20, '/':20}, 16)
    => 5+10-2*3+7+0+0+0+0+0+0+0 = 16
  • ( [2,3,5,7,10,0,0,0,0,0,0,0], {'+':20, '-':20, '*':20, '/':20}, 15)
    => 5+10+0*(2+3+7)+0+0+0+0+0+0 = 15

Є m = |L|? Якщо так, то як ви можете очікувати, що час виконання не залежатиме від розміру цього списку? Наприклад, [2,2],[+,+,...,+,/],1. Насправді, оскільки n - O (m), ви можете просто записати все це через m.
стенд

3
Яку арифметику використовувати для цього - точні дроби, ціле число ( /div), просто плаваюча точка і помилки з надією на відсутність округлення, ...?
перестали повертати проти годинника,

4
Чому складні правила балів для обчислювальної складності? Існує легке зменшення суми підмножини, тому щось краще, ніж O (2 ^ n), коштує мільйон доларів США.
Пітер Тейлор


1
3-й тестовий випадок не помилковий ...5+10+2*3+7*0+0...
Шміддті

Відповіді:


3

Python 2.7 / 478 символів

L=[17,5,9,17,59,14]
O={'+':7,'-':3,'*':5,'/':1}
N=569
P=eval("{'+l+y,'-l-y,'*l*y,'/l/y}".replace('l',"':lambda x,y:x"))
def S(R,T):
 if len(T)>1:
  c,d=y=T.pop();a,b=x=T.pop()
  for o in O:
   if O[o]>0 and(o!='/'or y[0]):
    T+=[(P[o](a, c),'('+b+o+d+')')];O[o]-=1
    if S(R,T):return 1
    O[o]+=1;T.pop()
  T+=[x,y]
 elif not R:
  v,r=T[0]
  if v==N:print r
  return v==N
 for x in R[:]:
  R.remove(x);T+=[x]
  if S(R,T):return 1
  T.pop();R+=[x]
S([(x,`x`)for x in L],[])

Основна ідея - використовувати постфікс-форму вирази для пошуку. Наприклад, 2*(3+4)у формі постфікса буде 234+*. Таким чином, проблема стає знаходженням частково перестановки L+, Oяка дорівнює N.

Наступна версія - це версія, що не має волі. Стек stkвиглядає так [(5, '5'), (2, '5-3', (10, ((4+2)+(2*(4/2))))].

L = [17, 5, 9, 17, 59, 14]
O = {'+':7, '-':3, '*':5, '/':1} 
N = 569

P = {'+':lambda x,y:x+y,
     '-':lambda x,y:x-y,
     '*':lambda x,y:x*y,
     '/':lambda x,y:x/y}

def postfix_search(rest, stk):
    if len(stk) >= 2:
        y = (v2, r2) = stk.pop()
        x = (v1, r1) = stk.pop()
        for opr in O:
            if O[opr] > 0 and not (opr == '/' and v2 == 0):
                stk += [(P[opr](v1, v2), '('+r1+opr+r2+')')]
                O[opr] -= 1
                if postfix_search(rest, stk): return 1
                O[opr] += 1
                stk.pop()
        stk += [x, y]
    elif not rest:
        v, r = stk[0]
        if v == N: print(r)
        return v == N
    for x in list(rest):
        rest.remove(x)
        stk += [x]
        if postfix_search(rest, stk):
            return True
        stk.pop()
        rest += [x]
postfix_search(list(zip(L, map(str, L))), [])

1
Нічого собі, це коротше, ніж я очікував. Я написав алгоритм, який включав в себе інфікс постфіксу <=> перетворення, але мій писар не був набагато коротшим, ніж ваша реалізація. Вражає. І дякую за будівництво P[opr](v1, v2). Я ніколи не думав поєднувати такі ламбди та словники, хоча зараз це здається очевидним.
Мартін Тома

Я спробував протестувати ваше рішення за допомогою мого 4-го тесту. Через 2 години я припинив страту.
Мартін Тома

@moose Я спробую додати трохи евристики, щоб зробити це швидше. Але після цього довжина коду може подвоїтися.
Рей

Використання дробу, як я тут, вирішує проблему у вашій відповіді. Просто спробуйте його для даного примірника на наданому посиланням. Ваш поточний код не знаходить відповіді, але при використанні дробу він робить.
Мартін Тома
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.