Wygeneruj liczbę, korzystając z podanej listy liczb i operatorów arytmetycznych

11

Otrzymasz listę liczb L = [17, 5, 9, 17, 59, 14], torbę operatorów O = {+:7, -:3, *:5, /:1}i numer N = 569.

Zadanie

Wyprowadź równanie, które używa wszystkich liczb Lpo lewej stronie i tylko liczby Npo prawej stronie. Jeśli nie jest to możliwe, wypisz False. Przykładowe rozwiązanie:

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

Ograniczenia i wyjaśnienia

  • Nie można [13,37]łączyć liczb ( nie można ich używać jako 1337)
  • Pojawią się tylko liczby naturalne i zero L.
  • Kolejność Lnie ma znaczenia.
  • Musisz użyć wszystkich cyfr w L.
  • Tylko podmioty +, -, *, /pojawi się O.
  • Omoże mieć więcej operatorów niż potrzebujesz, ale przynajmniej |L|-1operatorów
  • Możesz użyć każdego operatora dowolną liczbę razy, aż do wartości w O.
  • Wszystkie cztery operacje Osą standardowymi operacjami matematycznymi; w szczególności /jest to normalny podział z dokładnymi ułamkami.

Zwrotnica

  • Im mniej punktów, tym lepiej
  • Każdy znak kodu daje jeden punkt

Musisz dostarczyć wersję bez gry w golfa, która jest łatwa do odczytania.

tło

Podobne pytanie został poproszony na przepełnienie stosu. Pomyślałem, że może to być interesujące wyzwanie dla golfa.

Złożoność obliczeniowa

Jak powiedział Peter Taylor w komentarzach, możesz rozwiązać sumę podzbiorów za pomocą:

  1. Masz instancję sumy podzbioru (stąd zestaw S liczb całkowitych i liczby x)
  2. L: = S + [0, ..., 0] (| S | razy zero), N: = x, O: = {+: | S | -1, *: | S | - 1, /: 0, -: 0}
  3. Teraz rozwiąż ten przykład mojego problemu
  4. Rozwiązaniem dla sumy podzbiorów są liczby S, które nie są mnożone przez zero.

Jeśli znajdziesz algorytm lepszy niż O (2 ^ n), udowodnisz, że P = NP. Ponieważ P vs NP to problem z nagrodą milenijną, a zatem warty 1 000 000 dolarów amerykańskich, jest bardzo mało prawdopodobne, aby ktoś znalazł na to rozwiązanie. Więc usunąłem tę część rankingu.

Przypadki testowe

Poniższe nie są jedynymi prawidłowymi odpowiedziami, istnieją inne rozwiązania i są dozwolone:

  • ( [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
Martin Thoma
źródło
Jest m = |L|? Jeśli tak, to jak możesz oczekiwać, że środowisko wykonawcze nie będzie zależeć od wielkości tej listy? Na przykład [2,2],[+,+,...,+,/],1. W rzeczywistości, skoro n oznacza O (m), możesz po prostu napisać to wszystko w kategoriach m.
stoisko
3
Jakiego rodzaju arytmetyki należy użyć - dokładne ułamki zwykłe , liczba całkowita ( /div), tylko liczby zmiennoprzecinkowe i błędy braku zaokrąglania, ...
przestał się obracać w lewo o
4
Dlaczego skomplikowane reguły punktacji dla złożoności obliczeniowej? Łatwo jest zmniejszyć sumę częściową, więc cokolwiek lepszego niż O (2 ^ n) jest warte milion USD.
Peter Taylor
1
Powiązane: stackoverflow.com/questions/3947937/…
Dr Belisarius
1
Trzeci przypadek testowy nie jest fałszywy ...5+10+2*3+7*0+0...
Shmiddty

Odpowiedzi:

3

Znaki 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],[])

Główną ideą jest użycie do wyszukiwania wyrażenia postfiksowego. Na przykład 2*(3+4)w postaci Postfiksa będzie 234+*. Problemem staje się więc znalezienie częściowej permutacji L+, Októra ewaluuje N.

Następująca wersja jest wersją bez golfa. stkWygląda na to, że stos [(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))), [])
Promień
źródło
1
Wow, to krócej niż się spodziewałem. Zanotowałem algorytm, który zawierał postfiks konwersji <=>, ale moja bazgroła nie była dużo krótsza niż twoja implementacja. Imponujące. I dzięki za budowę P[opr](v1, v2). Nigdy nie myślałem o połączeniu lambdas i takich słowników, chociaż wydaje się to teraz oczywiste.
Martin Thoma
Próbowałem przetestować twoje rozwiązanie na mojej czwartej walizce testowej. Po 2 godzinach zatrzymałem egzekucję.
Martin Thoma
@moose Spróbuję dodać trochę heurystyki, aby była szybsza. Ale potem długość kodu może się podwoić.
Ray
Używanie Fraction, tak jak tutaj, naprawia problem w twojej odpowiedzi. Po prostu spróbuj dla danego wystąpienia na podany przeze mnie link. Twój obecny kod nie znajduje odpowiedzi, ale kiedy używasz ułamka, to robi.
Martin Thoma,