Générer un nombre en utilisant une liste donnée de nombres et d'opérateurs arithmétiques

11

On vous donne une liste de numéros L = [17, 5, 9, 17, 59, 14], un sac d'opérateurs O = {+:7, -:3, *:5, /:1}et un numéro N = 569.

Tâche

Générez une équation qui utilise tous les nombres Ldu côté gauche et uniquement le nombre Ndu côté droit. Si ce n'est pas possible, sortez False. Exemple de solution:

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

Limitations et clarification

  • Vous ne pouvez pas concaténer des numéros ( [13,37]ne peut pas être utilisé comme 1337)
  • Seuls les nombres naturels et zéro apparaîtront dans L.
  • L'ordre Ln'a pas d'importance.
  • Vous devez utiliser tous les chiffres dans L.
  • Seuls les opérateurs +, -, *, /apparaîtront O.
  • Opeut avoir plus d'opérateurs que vous n'en avez besoin, mais au moins les |L|-1opérateurs
  • Vous pouvez utiliser chaque opérateur autant de fois que vous le souhaitez O.
  • Les quatre opérations dans Osont les opérations mathématiques standard; en particulier, /est une division normale avec des fractions exactes.

Points

  • Moins il y a de points, mieux c'est
  • Chaque caractère de votre code vous donne un point

Vous devez fournir une version sans golf facile à lire.

Contexte

Une question similaire a été posée sur Stack Overflow. Je pensais que cela pourrait être un défi de golf de code intéressant.

Complexité informatique

Comme l'a dit Peter Taylor dans les commentaires, vous pouvez résoudre la somme des sous-ensembles avec ceci:

  1. Vous avez une instance de somme de sous-ensemble (d'où un ensemble S d'entiers et un nombre x)
  2. L: = S + [0, ..., 0] (| S | fois un zéro), N: = x, O: = {+: | S | -1, *: | S | - 1, /: 0, -: 0}
  3. Maintenant, résolvez cette instance de mon problème
  4. La solution pour la somme des sous-ensembles est le nombre de S qui ne sont pas multipliés par zéro.

Si vous trouvez un algorithme meilleur que O (2 ^ n), vous prouvez que P = NP. Comme P vs NP est un problème de prix du millénaire et vaut donc 1 000 000 de dollars américains, il est très peu probable que quelqu'un trouve une solution à cela. J'ai donc supprimé cette partie du classement.

Cas de test

Les réponses suivantes ne sont pas les seules valides, d'autres solutions existent et sont autorisées:

  • ( [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
la source
Est-ce m = |L|? Si oui, comment pouvez-vous vous attendre à ce que le runtime ne dépende pas de la taille de cette liste? Par exemple [2,2],[+,+,...,+,/],1,. En fait, puisque n est O (m), vous pourriez simplement tout écrire en termes de m.
stand
3
Quel type d'arithmétique est-ce à utiliser - fractionnaires exacts, entier ( /div), juste des erreurs à virgule flottante et sans espoir d'arrondi, ...?
cessé de tourner dans le sens inverse des aiguilles d'une montre le
4
Pourquoi les règles de notation compliquées pour la complexité de calcul? Il y a une réduction facile par rapport à la somme des sous-ensembles, donc quelque chose de mieux que O (2 ^ n) vaut un million USD.
Peter Taylor
1
Connexe: stackoverflow.com/questions/3947937/…
Dr. belisarius
1
Le 3ème cas de test n'est pas faux ...5+10+2*3+7*0+0...
Shmiddty

Réponses:

3

Caractères 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],[])

L'idée principale est d'utiliser la forme postfixe d'une expression pour rechercher. Par exemple, 2*(3+4)sous forme de suffixe sera 234+*. Le problème devient donc de trouver une permutation partielle de L+ Oqui s'évalue N.

La version suivante est la version non golfée. La pile stkressemble [(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))), [])
Rayon
la source
1
Wow, c'est plus court que ce à quoi je m'attendais. J'ai griffonné un algorithme qui incluait un infixe de conversion <=> postfix, mais mon griffonnage n'était pas beaucoup plus court que votre implémentation. Impressionnant. Et merci pour la construction P[opr](v1, v2). Je n'ai jamais pensé à combiner des lambdas et des dictionnaires comme celui-ci, bien que cela semble évident maintenant.
Martin Thoma
J'ai essayé de tester votre solution avec mon 4ème boîtier de test. Après 2h, j'ai arrêté l'exécution.
Martin Thoma
@moose Je vais essayer d'ajouter de l'heuristique pour le rendre plus rapide. Mais après cela, la longueur du code peut doubler.
Ray
L'utilisation de Fraction comme je l'ai fait ici résout un problème dans votre réponse. Essayez-le pour l'instance donnée sur le lien que j'ai fourni. Votre code actuel ne trouve pas de réponse, mais lorsque vous utilisez la fraction, il le fait.
Martin Thoma