Faites des mathématiques avec des allumettes minimales

15

Méta-fond

Cela a été défini comme une question sur Puzzling , et la réaction instantanée a été "eh bien, quelqu'un va simplement résoudre cela par ordinateur". Il y a eu un débat sur la complexité d'un programme pour résoudre ce problème. Eh bien, "à quel point ce programme doit être complexe" est à peu près la définition de , alors peut-être que PPCG peut régler le problème?

Contexte

Une équation d'allumette est fondamentalement une équation mathématique normale, mais où les chiffres et les opérateurs sont construits physiquement en plaçant des allumettes sur une table. (La principale caractéristique pertinente des allumettes ici est qu'elles sont assez rigides et ont une longueur constante; parfois, les gens utilisent d'autres objets à la place, tels que des cotons-tiges.)

Pour ce défi, nous n'avons pas besoin de définir de règles spécifiques pour la disposition des allumettes (comme le fait le défi lié); nous nous soucions plutôt du nombre d'allumettes dont nous aurons besoin pour représenter une expression qui évalue un nombre donné.

La tâche

Voici un alphabet de chiffres et d'opérateurs mathématiques que vous pouvez utiliser, chacun ayant un coût en allumettes:

  • 0, coûtant 6 allumettes
  • 1, coûtant 2 allumettes
  • 2, coûtant 5 allumettes
  • 3, coûtant 5 allumettes
  • 4, coûtant 4 allumettes
  • 5, coûtant 5 allumettes
  • 6, coûtant 6 allumettes
  • 7, coûtant 3 allumettes
  • 8, coûtant 7 allumettes
  • 9, coûtant 6 allumettes
  • +, coûtant 2 allumettes
  • -, coûtant 1 allumette
  • ×, coûtant 2 allumettes

(Vous pouvez représenter ×comme *dans la sortie de votre programme si vous le souhaitez, afin d'éviter d'avoir à utiliser des caractères non ASCII. Dans la plupart des encodages, ×prend plus d'octets que *, et donc j'imagine que la plupart des programmes voudront profiter de cette latitude .)

Vous devez écrire un programme qui prend un entier non négatif en entrée (via tout moyen raisonnable ) et produit une expression qui évalue cet entier en sortie (à nouveau via tout moyen raisonnable). De plus, l'expression doit être triviale: il doit contenir au moins un opérateur +, -ou× . Enfin, l'expression que vous produisez doit être la moins chère (ou liée pour la moins chère) en termes de coût total de matchstick, parmi toutes les sorties qui autrement sont conformes à la spécification.

Clarifications

  • Vous pouvez former des nombres à plusieurs chiffres via la sortie de plusieurs chiffres consécutifs (par exemple, 11-1une sortie valide à produire 10). Pour être tout à fait précis, le nombre résultant est interprété en décimal. Ce type de concaténation n'est pas une opération qui fonctionne sur des résultats intermédiaires; uniquement sur les chiffres littéraux qui apparaissent dans l'expression d'origine.
  • Aux fins de ce défi. +, -Et ×sont des opérateurs infixes; ils ont besoin d'un argument à leur gauche et à leur droite. Vous n'êtes pas autorisé à les utiliser en position de préfixe comme +5ou -8.
  • Vous n'avez pas de parenthèses (ou tout autre moyen de contrôler la priorité) disponibles. L'expression est évaluée selon les règles de priorité par défaut typiques (les multiplications se produisent d'abord, puis les additions et les soustractions sont évaluées de gauche à droite).
  • Vous n'avez accès à aucun opérateur ou constante mathématique autre que ceux répertoriés ci-dessus; Les solutions de «pensée latérale» sont souvent acceptées chez Puzzling, mais cela n'a pas de sens d'exiger qu'un ordinateur les propose lui-même, et ici sur PPCG, nous aimons qu'il soit objectif qu'une solution soit correcte ou non.
  • Les règles habituelles de dépassement d'entier s'appliquent: votre solution doit pouvoir fonctionner pour des entiers arbitrairement grands dans une version hypothétique (ou peut-être réelle) de votre langue dans laquelle tous les entiers sont illimités par défaut, mais si votre programme échoue dans la pratique en raison de la mise en œuvre ne prenant pas en charge des entiers de cette taille, cela n'invalide pas la solution.
  • Si vous utilisez le même chiffre ou l'opérateur plus d'une fois, vous devez payer son coût d'allumette chaque fois que vous l'utilisez (car, évidemment, vous ne pouvez pas réutiliser les mêmes allumettes physiques à deux endroits différents sur la table).
  • Il n'y a pas de limite de temps; les solutions de force brute sont acceptables. (Bien que si vous avez une solution plus rapide que la force brute, n'hésitez pas à la publier même si elle est plus longue; voir comment comparer les approches alternatives est toujours intéressant.)
  • Bien que l'écriture d'une explication de votre code ne soit jamais requise , c'est probablement une bonne idée; solutions de sont souvent très difficiles à lire (en particulier pour les personnes qui ne connaissent pas la langue dans laquelle elles sont écrites), et il peut être difficile d'évaluer (et donc de voter) une solution à moins de comprendre comment elle fonctionne.

Condition de victoire

En tant que défi de , les réponses avec moins d'octets sont considérées comme meilleures. Cependant, comme d'habitude, n'hésitez pas à publier des réponses avec des approches différentes, ou dans des langues spécifiques même si elles sont plus verbeuses que certaines autres langues; le but du golf est vraiment de voir dans quelle mesure vous pouvez optimiser un programme particulier, et faire les choses de cette façon nous donne beaucoup de programmes potentiels à optimiser. Ne vous découragez donc pas si quelqu'un soumet une solution en utilisant une approche complètement différente, ou une langue complètement différente, et obtient une réponse beaucoup plus courte; il se pourrait bien que votre réponse soit mieux optimisée et montre plus de compétence, et les électeurs de PPCG l'apprécient souvent.

Communauté
la source
Jeez, quel est le nombre le plus élevé que nous devons gérer? Ma tentative actuelle ne se poursuivrait pas comme ... peut-être 20 sur TIO.
Magic Octopus Urn
@carusocomputing: Arbitrairement élevé en théorie , mais si vous ne pouvez pas dépasser 20 dans un délai raisonnable dans la pratique, c'est tout à fait acceptable.
4
Avez-vous des cas de test?
Luke
Je souhaite vraiment que ce soit une seule opération, répartie contre plusieurs compétitions. La multiplication est un problème de diviseur, mais l'ajout et la soustraction compliquent vraiment les choses. J'ai une solution qui fonctionne, mais pas pour l'addition et la soustraction; faire ce travail parfaitement sera fastidieux.
Urne Magic Octopus
@carusocomputing: Vous pourriez alors être intéressé par ce défi . Je soupçonne que le défi avec la multiplication seulement est significativement différent et nécessiterait des techniques de solution plutôt différentes pour obtenir un bon score.

Réponses:

1

Python2, 1̶9̶8̶ ̶b̶y̶t̶e̶s̶ 182 octets grâce à math_junkie

def f(n,c=dict(zip('0123456789+-*',map(int,'6255456376212'))),e=[(0,'')]):
 while 1:
    v=(m,s)=min(e);e.remove(v)
    try:
     if eval(s)==n:return s
    except:0
    e+=[(m+c[x],s+x)for x in c]

Cet algorithme ne fait rien pour exclure les versions préfixées de +et -, mais elles seront soit pires, soit égales et apparaîtront plus tard dans la recherche, leurs homologues infixes. Parce qu'il utilise l'argument mot clé de manière emutuelle, il donnera des résultats invalides s'il est appelé plusieurs fois par session. Pour résoudre ce problème, utilisez f(n, e=[(0,'')])plutôt que juste f(n). Notez que les retraits à quatre espaces représentent des tabulations, donc cela ne fonctionnera qu'avec Python 2.

J'ai également une version non golfée et optimisée qui s'exécute rapidement même pour un assez grand nombre:

from heapq import heappop, heappush

def f(n):
    digits = list('0123456789')
    ops =['+','-','*','']
    costs = dict(zip(digits + ops, [6,2,5,5,4,5,6,3,7,6,2,1,2,0]))
    expressions = [(costs[d], abs(n - int(d)), int(d), d) for d in digits[1:]]
    seen = set()
    while 1:
        cost, d, k, expression = heappop(expressions)
        if d == 0:
            return expression
        for op in ops:
            if op in '+-' and k in seen:
                continue
            for digit in digits:
                if op and digit == '0':
                    continue
                expression1 = expression + op + digit
                k1 = eval(expression1)
                d1 = abs(n - k1)
                if d1 == 0:
                    return expression1
                heappush(expressions, (cost+costs[op]+costs[digit], d1, k1, expression1))
        seen.add(k)
user1502040
la source
Quelques golfs mineurs suggérés: TIO (182 bytes)
math junkie
1

PHP, 241 octets

Version en ligne

function m($i){for(;$s<strlen($i);)$e+="6255456376"[$i[$s++]];return$e;}foreach($r=range(0,2*$a=$argv[1])as$v)foreach($r as$w)$x[$v+$w]["$v+$w"]=$x[$v*$w]["$v*$w"]=1+$x[$v-$w]["$v-$w"]=m("$v")+m("$w")+1;echo array_search(min($x[$a]),$x[$a]);

Panne

function m($i){
    for(;$s<strlen($i);)$e+="6255456376"[$i[$s++]];return$e; #return the count of the matchstick for an integer
}

foreach($r=range(0,2*$a=$argv[1])as$v) # limit to an input to 300 in the online version
foreach($r as$w)
       $x[$v+$w]["$v+$w"]=  #fill the 2D array in the form [result][expression] = count matchsticks
       $x[$v*$w]["$v*$w"]=
       1+$x[$v-$w]["$v-$w"]=
       m("$v")+m("$w")+1;
echo $k=array_search(min($x[$a]),$x[$a]); # Output expression with a minium of matchsticks
echo"\t".$x[$a][$k]; #optional Output of the count of the matchsticks

Chemin avec un peu de meilleures performances

function m($i){
for(;$s<strlen($i);)
$e+="6255456376"[$i[$s++]];return$e;} #return the count of the matchstick for an integer
foreach($r=range(0,2*$a=$argv[1])as$v)
foreach($r as$w){$c=m("$v")+m("$w")+1;
if($a==$v+$w)$x["$v+$w"]=1+$c; # fill array if value equal input
if($a==$v*$w)$x["$v*$w"]=1+$c;
if($a==$v-$w)$x["$v-$w"]=$c;}
echo $k=array_search(min($x),$x); # Output expression with a minium of matchsticks
    echo"\t".$x[$k]; #optional Output of the count of the matchsticks

Prise en charge d'entiers négatifs

Version avec des nombres négatifs

function m($i){
    $e=$i<0?1:0; # raise count for negative integers
    for($s=0;$s<strlen($i);)$e+=[6,2,5,5,4,5,6,3,7,6][$i[$s++]];return$e; #return the count of the matchstick for an integer
}
$q=sqrt(abs($argv[1]));
$l=max(177,$q);
$j=range(-$l,$l); # for second loop for better performance
foreach($r=range(min(0,($a=$argv[1])-177),177+$a)as$v) 
foreach($j as$w){$c=m("$v")+m("$w")+1;  
    if($a==$v+$w)$x["$v+$w"]=1+$c; # fill array if value equal input
    if($a==$v*$w)$x["$v*$w"]=1+$c;
    if($a==$v-$w)$x["$v-$w"]=$c;
    if($a==$w-$v)$x["$w-$v"]=$c; # added for integers <0
}
echo $k=array_search(min($x),$x); # Output expression with a minium of matchsticks
echo"\t".$x[$k]; #optional Output of the count of the matchsticks
Jörg Hülsermann
la source
Oh snap, cela fonctionne aussi sur les nombres négatifs!
Magic Octopus Urn
@carusocomputing pas vraiment il se pourrait qu'une solution existe avec moins d'allumettes car les nombres négatifs ne sont ajoutés que par soustraction. dans ce cas, vous devez également vérifier la valeur absolue et en ajouter une
Jörg Hülsermann
Je ne pense pas que le 333 littéral serait acceptable ici, bien que vous puissiez probablement le corriger en lui faisant une fonction de l'entrée. (Le programme pourrait bien fonctionner beaucoup plus lentement, vous pouvez donc conserver la version codée en dur pour les tests.)
1
@ ais523 done 333 est remplacé par une entrée 2 *
Jörg Hülsermann
1
Vous pouvez les chaînes d'index: $e+="6255456376"[$i[$s++]];.
manatwork