Crea matematica con fiammiferi minimi


15

Meta-sfondo

Questo è stato posto come una domanda su Puzzle , e la reazione istantanea è stata "beh, qualcuno lo risolverà semplicemente al computer". C'è stato un dibattito su quanto complesso dovrebbe essere un programma per risolvere questo problema. Bene, "quanto deve essere complesso questo programma" è praticamente la definizione di , quindi forse PPCG può risolvere il problema?

sfondo

Un'equazione fiammifero è fondamentalmente una normale equazione matematica, ma dove le cifre e gli operatori sono costruiti fisicamente mettendo fiammiferi su un tavolo. (La principale caratteristica rilevante dei fiammiferi qui è che sono abbastanza rigidi e hanno una lunghezza costante; a volte le persone usano invece altri oggetti, come i bastoncini di cotone.)

Per questa sfida, non è necessario definire regole specifiche per l'organizzazione dei matchsticks (come fa la sfida collegata); piuttosto, ci preoccupiamo solo di quanti fiammiferi avremo bisogno di rappresentare un'espressione che valuti un determinato numero.

L'obiettivo

Ecco un alfabeto di cifre e operatori matematici che puoi usare, ognuno con un costo in fiammiferi:

  • 0, costando 6 fiammiferi
  • 1, costando 2 fiammiferi
  • 2, costando 5 fiammiferi
  • 3, costando 5 fiammiferi
  • 4, costando 4 fiammiferi
  • 5, costando 5 fiammiferi
  • 6, costando 6 fiammiferi
  • 7, che costa 3 fiammiferi
  • 8, che costa 7 fiammiferi
  • 9, costando 6 fiammiferi
  • +, costando 2 fiammiferi
  • -, che costa 1 fiammifero
  • ×, costando 2 fiammiferi

( Se lo desideri, puoi rappresentare ×come *nell'output del tuo programma, al fine di evitare la necessità di utilizzare caratteri non ASCII. Nella maggior parte delle codifiche, ×occupa più byte di *, e quindi immagino che la maggior parte dei programmi vorrà sfruttare questo margine di manovra .)

È necessario scrivere un programma che accetta un intero non negativo come input (tramite qualsiasi mezzo ragionevole ) e produce un'espressione che restituisce tale intero come output (di nuovo tramite qualsiasi mezzo ragionevole). Inoltre, l'espressione deve essere non banale: deve contenere almeno un operatore +, -o ×. Infine, l'espressione che produci deve essere la più economica (o legata a quella più economica) in termini di costo totale del matchstick, tra tutte le uscite che altrimenti rispettano le specifiche.

chiarimenti

  • È possibile formare numeri a più cifre emettendo più cifre in una riga (ad esempio, 11-1è un output valido da produrre 10). Per essere completamente precisi, il numero risultante viene interpretato in decimale. Questo tipo di concatenazione non è un'operazione che funziona su risultati intermedi; solo su cifre letterali che compaiono nell'espressione originale.
  • Ai fini di questa sfida. +, -e ×sono operatori infix; hanno bisogno di una discussione alla loro sinistra e alla loro destra. Non ti è consentito usarli in posizione prefisso come +5o -8.
  • Non hai parentesi (o altri modi per controllare la precedenza) disponibili. L'espressione viene valutata in base alle tipiche regole di precedenza predefinite (le moltiplicazioni si verificano prima, quindi le aggiunte e le sottrazioni vengono valutate da sinistra a destra).
  • Non hai accesso ad operatori matematici o costanti diversi da quelli sopra elencati; Le soluzioni di "pensiero laterale" sono spesso accettate in Puzzling, ma non ha senso richiedere che un computer le sviluppi da solo, e qui su PPCG, ci piace che sia obiettivo se una soluzione sia corretta o meno.
  • Si applicano le solite regole di overflow dei numeri interi: la soluzione deve essere in grado di funzionare per numeri interi arbitrariamente grandi in una versione ipotetica (o forse reale) della lingua in cui tutti i numeri interi non sono associati per impostazione predefinita, ma se il programma non riesce in pratica a causa dell'implementazione non supportando numeri interi così grandi, ciò non invalida la soluzione.
  • Se usi la stessa cifra o operatore più di una volta, devi pagare il suo costo di fiammifero ogni volta che lo usi (perché, ovviamente, non puoi riutilizzare gli stessi fiammiferi fisici in due diverse posizioni sul tavolo).
  • Non c'è limite di tempo; le soluzioni a forza bruta sono accettabili. (Anche se hai una soluzione più veloce della forza bruta, sentiti libero di pubblicarla anche se è più lunga; vedere come il confronto di approcci alternativi è sempre interessante.)
  • Sebbene non sia mai necessario scrivere una spiegazione del codice , è probabile che sia una buona idea; soluzioni di sono spesso molto difficili da leggere (specialmente per le persone che non hanno familiarità con la lingua in cui sono scritte), e può essere difficile valutare (e quindi votare) una soluzione a meno che tu non capisca come funziona.

Condizione di vittoria

Come sfida del , le risposte con meno byte sono considerate migliori. Tuttavia, come al solito, sentiti libero di pubblicare risposte con approcci diversi o in lingue specifiche anche se sono più dettagliate di certe altre lingue; l'obiettivo del golf è davvero vedere fino a che punto è possibile ottimizzare un determinato programma, e fare le cose in questo modo ci offre molti potenziali programmi da ottimizzare. Quindi non scoraggiarti se qualcuno invia una soluzione utilizzando un approccio completamente diverso o una lingua completamente diversa e ottiene una risposta molto più breve; può darsi che la tua risposta sia meglio ottimizzata e mostri più abilità, e gli elettori su PPCG lo apprezzano spesso.


Accidenti, qual è il numero più alto che dobbiamo gestire? Il mio attuale tentativo non andrebbe oltre come ... forse 20 su TIO.
Magic Octopus Urn

@carusocomputing: arbitrariamente alto in teoria , ma se non riesci a superare i 20 entro un tempo ragionevole in pratica, è del tutto accettabile.

4
Hai dei casi di test?
Luca

Vorrei davvero che si trattasse di un'unica operazione, diffusa contro più competizioni. La moltiplicazione è un problema divisore, ma l'aggiunta di addizioni e sottrazioni complica davvero le cose. Ho una soluzione che funziona, ma non per l'aggiunta e la sottrazione; far funzionare perfettamente sarà noioso.
Magic Octopus Urn

@carusocomputing: potresti essere interessato a questa sfida , allora. Sospetto che la sfida con la moltiplicazione sia significativamente diversa e richiederebbe tecniche di soluzione piuttosto diverse per ottenere un buon punteggio.

Risposte:


1

Python2, 1̶9̶8̶ ̶b̶y̶t̶e̶s̶ 182 byte grazie a 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]

Questo algoritmo non fa nulla per escludere le versioni di prefisso +e -, ma saranno o peggiori o uguali e compaiono più avanti nella ricerca, le loro controparti infix. Poiché utilizza emutuamente l' argomento della parola chiave , darà risultati non validi se chiamato più volte per sessione. Per risolvere questo problema, utilizzare f(n, e=[(0,'')])invece di solo f(n). Nota che i rientri a quattro spaziature rappresentano le schede, quindi funzionerà solo con Python 2.

Ho anche una versione non ottimizzata e ottimizzata che funziona rapidamente anche per numeri abbastanza grandi:

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)

Alcuni campi da golf suggeriti minori: TIO (182 byte)
drogato di matematica il

1

PHP, 241 byte

Versione online

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]);

Abbattersi

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

Modo con prestazioni leggermente migliori

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

Supporto di numeri interi negativi

Versione con numeri interi negativi

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

Oh schiocco, funziona anche su numeri negativi!
Magic Octopus Urn

@carusocomputing non potrebbe essere che esistesse una soluzione con meno fiammiferi perché i numeri negativi vengono aggiunti solo per sottrazione. in questo caso dovresti controllare anche il valore assoluto e aggiungerne uno
Jörg Hülsermann

Non credo che il 333 letterale sarebbe accettabile qui, anche se probabilmente potresti risolverlo rendendolo una funzione dell'input. (Il programma potrebbe funzionare molto più lentamente, quindi potresti mantenere la versione hardcoded per i test.)

1
@ ais523 fatto 333 viene sostituito con 2 * input
Jörg Hülsermann

1
È possibile stringhe indice: $e+="6255456376"[$i[$s++]];.
arte
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.