Esprimi un numero con solo 0-9 e le quattro operazioni


14

Spiegazione

Befunge è un programma bidimensionale che utilizza stack .

Ciò significa che, per fare 5 + 6, scrivi 56+, nel senso:

56+
5    push 5 into stack
 6   push 6 into stack
  +  pop the first two items in the stack and add them up, and push the result into stack

(to those of you who do not know stacks, "push" just means add and "pop" just means take off)

Tuttavia, come ha notato l'intelligente di voi, non possiamo inserire il numero 56direttamente nello stack.

Per fare ciò, dobbiamo scrivere 78*, invece, che moltiplica 7e 8e spinge il prodotto nello stack.

Dettagli

L'input può essere preso in qualsiasi formato, nel senso che può essere STDIN o meno, a discrezione del programmatore.

L'input sarà un numero intero positivo (nessun bonus per 0numeri interi inclusi o negativi).

L'uscita sarà una stringa costituita solo questi caratteri: 0123456789+-*/(io non usare% . Modulo)

L'obiettivo è trovare la stringa più corta che possa rappresentare l'input, usando il formato sopra descritto.

Ad esempio, se l'input è 123, allora l'output sarebbe 67*99*+. L'output deve essere valutato da sinistra a destra.

Se esistono più uscite accettabili (ad es 99*67*+ è anche accettabile), uno può essere stampata (senza bonus per la stampa di tutti).

Ulteriori spiegazioni

Se ancora non capisci come 67*99*+valuta 123, ecco una spiegazione dettagliata.

stack    |operation|explanation
          67*99*+
[6]       6         push 6 to stack
[6,7]      7        push 7 to stack
[42]        *       pop two from stack and multiply, then put result to stack
[42,9]       9      push 9 to stack
[42,9,9]      9     push 9 to stack
[42,81]        *    pop two from stack and multiply, then put result to stack
[123]           +   pop two from stack and add, then put result to stack

TL; DR

Il programma deve trovare il più breve stringa che può rappresentare l'input (numero), usando il formato sopra specificato.

Appunti

Questa è una sfida di , quindi vince il codice più breve in byte.

disambiguation

Il -possono essere sia x-yo y-x, a discrezione del programmatore. Tuttavia, la scelta deve essere coerente all'interno della soluzione. Allo stesso modo per il /.

Programma di esempio

Lua, 1862 byte ( provalo online )

Dal momento che sono l'autore, non lo golfò affatto.

Spiegazione:

This uses the depth-first search method.

Ulteriori informazioni sulla ricerca approfondita: qui .

Il programma:

local input = (...) or 81

local function div(a,b)
    if b == 0 then
        return "error"
    end
    local result = a/b
    if result > 0 then
        return math.floor(result)
    else
        return math.ceil(result)
    end
end

local function eval(expr)
    local stack = {}
    for i=1,#expr do
        local c = expr:sub(i,i)
        if c:match('[0-9]') then
            table.insert(stack, tonumber(c))
        else
            local a = table.remove(stack)
            local b = table.remove(stack)
            if a and b then
                if c == '+' then
                    table.insert(stack, a+b)
                elseif c == '-' then
                    table.insert(stack, b-a)
                elseif c == '*' then
                    table.insert(stack, a*b)
                elseif c == '/' then
                    local test = div(b,a)
                    if test == "error" then
                        return -1
                    else
                        table.insert(stack, a+b)
                    end
                end
            else
                return -1
            end
        end
    end
    return table.remove(stack) or -1
end

local samples, temp = {""}, {}

while true do
    temp = {}
    for i=1,#samples do
        local s = samples[i]
        table.insert(temp, s..'0')
        table.insert(temp, s..'1')
        table.insert(temp, s..'2')
        table.insert(temp, s..'3')
        table.insert(temp, s..'4')
        table.insert(temp, s..'5')
        table.insert(temp, s..'6')
        table.insert(temp, s..'7')
        table.insert(temp, s..'8')
        table.insert(temp, s..'9')
        table.insert(temp, s..'+')
        table.insert(temp, s..'-')
        table.insert(temp, s..'*')
        table.insert(temp, s..'/')
    end
    for i=1,#temp do
        if input == eval(temp[i]) then
            print(temp[i])
            return
        end
    end
    samples = temp
end

indennità

Una torta per te se usi Befunge (o qualsiasi sua variante) per scrivere il codice.


3
Può essere difficile decidere, data una risposta, se produce sempre la stringa più ordinata. Un'idea sarebbe quella di generare un ampio set di dire 30-50 numeri e segnare con la somma di tutta la lunghezza della stringa di output. Tuttavia, non sono sicuro di come combinare quel punteggio con la lunghezza del codice
Luis Mendo

4
Sottoinsieme di questo .
Addison Crump,

2
Copiando i miei pensieri dalla chat : "Ci ho pensato, ma direi che il sottoinsieme rende le cose molto più semplici perché 1) nessun esagono, 2) nessun float, 3) nessuna duplicazione e 4) solo positivo"
Sp3000

1
@CoolestVeto questo è abbastanza diverso da invalidare le vecchie risposte.
Rɪᴋᴇʀ

1
@CoolestVeto Penso che l'altra sfida debba essere chiusa come duplicata di questa.
mbomb007,

Risposte:


4

Python 2, 278 byte

La mia migliore soluzione, che ogni volta dà la risposta più breve. (ma molto lento)

def e(c):
 s=[];x,y=s.append,s.pop
 while c:
  d,c=c[0],c[1:]
  if"/"<d<":":x(d)
  else:a,b=y(),y();x(str(eval(b+d+a)))
 return int(y())
def g(v):
 s="0123456789+-*";t=list(s)
 while 1:
  for x in t:
   try:
    if e(x)==v:return x
   except:0
  t=[x+y for x in t for y in s]

Python 2, 437 byte

Questa soluzione è più lunga, ma molto veloce (non forza bruta). E sono abbastanza sicuro che restituisca sempre il risultato più breve possibile.

r=range;l=len;a=input()
def f(n):
 if n<=9:return str(n)
 for d in r(9,1,-1):
  if n%d==0:return f(n/d)+"%d*"%d
 h=sum(map(int,list(str(n))))%9
 return f(n-h)+"%d+"%h
m={x:f(x) for x in r(a*9)}
for b in m:
 if a-b in m and l(m[b])+l(m[a-b])+1<l(m[a]):m[a]=m[a-b]+m[b]+"+"
 if a+b in m and l(m[b])+l(m[a+b])+1<l(m[a]):m[a]=m[a+b]+m[b]+"-"
 if b!=0 and a%b==0 and a/b in m and l(m[b])+l(m[a/b])+1<l(m[a]):m[a]=m[a/b]+m[b]+"*"
print m[a]

2
Benvenuti in PPCG ! Spero che ti divertirai qui.
Leaky Nun,

1
@pbochinak Penso di averne trovato uno valido. f(6551)ritorna 25*8*9*7+9*8+(13 caratteri), mentre 9999***52*-(11 caratteri) è migliore. Verificato con la mia evalfunzione sopra (nella domanda).
Leaky Nun,

4
@pbochniak Come sottolinea il commento prima del mio, questa risposta non è valida nel suo stato attuale. Si consiglia di eliminarlo temporaneamente mentre si sta lavorando su una correzione (se non altro, per evitare che attiri voti negativi).
Dennis,

1
il tuo tempo può essere solowhile c:
Ven

È possibile utilizzare ;per separare le assegnazioni alle variabili (che salva i byte in blocchi rientrati), il suggerimento di ven, eliminare lo spazio bianco tra un simbolo e qualsiasi altra cosa, e tpuò andare.
Calcolatrice

4

Perl, 134 133 132 128 byte

Include +5 per -Xlp(2 extra perché il codice contiene ')

Esegui con il numero di destinazione su STDIN:

perl -Xlp befour.pl <<< 123

befour.pl:

@1{1..9}=1..9;$.+=2,map{for$a(%1){"+-*/"=~s%.%"\$1{\$-=$a$&$_/'$1{$a}$1{$_}$&'=~/^.{$.}\$/}||=\$&"%eegr}}%1until$\=$1{$_}}{

Non ha limiti artificiali ed è concettualmente un po 'efficiente ma ha tempi di esecuzione terribili, anche se ho sacrificato qualche byte per accelerarlo. Generare una soluzione di lunghezza 11 (ad es. Numero obiettivo 6551) richiede circa 5 ore sul mio sistema.

Sacrificare altri 7 byte rende la velocità leggermente più sopportabile.

@1{1..9}=1..9;$.+=2,map{for$a(@a){"+-*/"=~s%.%"\$1{\$-=$a$&$_/'$1{$a}$1{$_}$&'=~/^.{$.}\$/}||=\$&"%eegr}}@a=keys%1until$\=$1{$_}}{

17 minuti per una soluzione di lunghezza 11, circa 5 ore per una soluzione di lunghezza 13. Il primo numero che richiede lunghezza 15 è 16622 che richiede circa 2 giorni. Il primo numero che richiede la lunghezza 17 è 73319.

Si noti che presuppone che la divisione restituisca un numero intero troncando verso 0 (secondo la specifica befunge 93)


Cosa fanno i segni del dollaro? (Non parlo affatto Perl)
Leaky Nun

1
@KennyLau $accede al valore scalare. Dove nella maggior parte delle lingue si scriverà a=4, perl utilizzerà $a=4. Ma viene anche utilizzato per un accesso scalare di variabili più complesse. Ad esempio, $a{$b}recupera dall'hash (mappa, dizionario) %ail valore scalare digitato$b
Ton Hospel

2

C, 550 545 byte

#define L strlen
#define y strcpy
#define t strcat
char c[9999][99];i=1,k=3;main(j){for(;i<10;i++)*c[i]=i+'0';for(;k--;){
for(i=1;i<9999;i++)for(j=1;j<=i;j++)*c[i]&&*c[j]&&(i+j>9998||*c[i+j]&&
L(c[i+j])<L(c[i])+L(c[j])+2||t(t(y(c[i+j],c[i]),c[j]),"+"),
i*j>9998||*c[i*j]&&L(c[i*j])<L(c[i])+L(c[j])+2||t(t(y(c[i*j],c[i]),c[j]),"*"));
for(i=9999;--i;)for(j=i;--j;)*c[i]&&*c[j]&&(*c[i/j]&&
L(c[i/j])<L(c[i])+L(c[j])+2||t(t(y(c[i/j],c[i]),c[j]),"/"),
*c[i-j]&&L(c[i-j])<L(c[i])+L(c[j])+2||t(t(y(c[i-j],c[i]),c[j]),"-"));}
scanf("%d",&i);printf("%s",c[i]);}

550 545 byte dopo aver eliminato le newline non necessarie (tutte tranne le tre newline dopo le direttive di preelaborazione).

@Kenny Lau - Può ricevere come input un numero intero compreso tra 1 e 9998, ma penso che l'intervallo di input per il quale viene calcolata una soluzione ottimale sia inferiore a 9998. D'altra parte, entrambi gli intervalli possono essere estesi, se la memoria lo permette.

Il programma non può spingere nello stack alcun numero superiore a 9998. (9998 può essere modificato.) Ho eseguito il programma in una versione diversa, ripetendo il ciclo esterno (quello con k) finché c'è un miglioramento per qualsiasi numero tra 1 e 9998 (come nell'algoritmo di Dijkstra). Dopo tre iterazioni non ci sono miglioramenti. Quindi per salvare i byte, ho hardcoded k = 3.

Per estendere l'intervallo, sono necessarie due cose: modificare le costanti 9999 e 9998, eseguendolo con un numero variabile di iterazioni sul ciclo esterno per tutto il tempo in cui c'è un miglioramento, per vedere quanto tempo impiega fino a quando non si verifica alcun miglioramento, quindi modifica la costante k = 3 su quel valore.


Benvenuti in PPCG ! Spero che ti divertirai qui.
Leaky Nun,

Questo ha superato perfettamente il mio test 6551. Qual è la gamma effettiva di questo programma?
Leaky Nun,

Credo che sia 9999. Potete per favore aggiungere queste informazioni alla vostra soluzione?
Leaky Nun,

Dovrebbe essere 9998. Inoltre, si può mangiare alcuni byte per l'inizializzazione i, je kprima main().
Leaky Nun,

1
@Kenny Lau - Grazie per la modifica. Per quanto riguarda l'estensione della gamma, ho notato che in realtà ci vuole un po 'di più per estenderla. Ho incluso tali informazioni nella risposta.
mIllIbyte

2

Python 2, 284 byte

Disclaimer: prende per sempre il pazzo per alcuni valori ... ma dovrebbe essere garantito per restituire sempre la stringa più corta e non ha limiti di intervallo imposti artificialmente ... funziona anche su valori negativi. :)

def f(v):
 i,z=0,'+-*/'
 while 1:
  s=('%x'%i).translate(__import__('string').maketrans('abcd',z),'ef');t=s;q=[];a,p=q.append,q.pop;i+=1
  try:
   while t:
    o,t=t[0],t[1:]
    if o in z:n,m=p(),p();a(eval(`m`+o+`n`))
    else:a(int(o))
   if p()==v and not q:return s
  except:pass

Algoritmo:

  • Iniziare con i = 0
  • Prendi la stringa che rappresenta il valore esadecimale di i, e sostituisci rispettivamente abcdcon +-*/e rimuovi qualsiasief
  • Tentativo di elaborare la stringa come notazione postfix (RPN)
  • Se ha esito positivo e il risultato corrisponde al valore di input, restituisce la stringa utilizzata.
  • Altrimenti, incrementa ie riprova.

"[t] akes [...] per sempre per alcuni valori" L'hai provato? Quali valori?
Leaky Nun,

@KennyLau Ho appena scritto un test che è il calcolo f(i)da 0 <= i <= 6551(per catturare il 6551valore utilizzato per invalidare @pbochniak 's presentazione originale). In questo momento, è in esecuzione solo da pochi minuti, ed ecco l'ultimo risultato del test: 91 : 49+7* 3.020 s (total 108.174 s, worst 89: 5.827 s) Aggiornamento - è appena finito con il valore 92: 92 : 149+7*+ 258.761 s (total 366.935 s, worst 92: 258.761 s)
Ken 'Joey' Mosher

@KennyLau: Il test dura da un'ora e solo fino a un valore 113... vedi l'output del test completo qui (pastebin) se sei interessato ...
Ken 'Joey' Mosher

2

Python 2, 182 byte

n=input()
L=[[[],""]]
while 1:
 s,c=L.pop(0);L+=[[s+[i],c+`i`]for i in range(10)]+(s[1:]and[[s[:-2]+[eval(`s[-2]`+o+`s[-1]`)],c+o]for o in"/+-*"[s[-1]==0:]])
 if[n]==s[-1:]:print c;E

Così oscenamente lento, l'ho lasciato in funzione per un'ora in ingresso 221e ancora non è terminato. Gran parte della lentezza è perché sto usando un elenco come una coda per una prima ricerca, ed .pop(0)èO(n) per le liste.

Lè solo una coda contenente (stack, code to reach stack)coppie. Ad ogni passaggio, le cifre vengono sempre aggiunte e gli operatori vengono eseguiti se lo stack ha almeno due elementi. La divisione viene eseguita solo se l'ultimo elemento non è 0, anche se ho il forte sospetto che la divisione non sia mai necessaria (anche se non ho modo di provarlo, ma ho verificato che questo è il caso fino a 500).

Il programma termina tramite a NameError dopo la stampa del risultato (eventualmente).


Cosa sta ;Efacendo alla fine?
Leaky Nun,

@KennyLau Questo è il NameErrortermine, poiché Enon è definito altrove
Sp3000

Caspita, tanta intelligenza.
Leaky Nun,

1

CJam, 79

ri:M;A,:s:L;{L2m*{s,Y=},{~:A+AS*~!"/+-*">\f{\+}~}%Y2+:Y;_L@+:L;{S*~M=},:R!}gR0=

Provalo online

Questo è orribilmente inefficiente, ma dato abbastanza memoria e tempo, alla fine funziona. 123 esaurisce la memoria con 16 GB, ma 120 e 125 sono ok.


1

Pyth - 35 byte

Forza bruta. Una cosa strana è che il nuovo input implicito in realtà danneggia il mio punteggio perché sembra funzionare anche per .vpyth_eval.

.V1IKfqQ.x.v+jd_T\;N^s+"+-*/"UTbhKB

Provalo online qui .


0

Python 3, 183 byte

e,n=enumerate,input()
v=list('0123456789')+[' '*n]*n*2
for i,s in e(v):
 for j,t in e(v):
  for o,k in zip('+*-',(i+j,i*j,i-j)):
   if 9<k<2*n:v[k]=min(v[k],s+t+o,key=len)
print(v[n])

La velocità non è del tutto irragionevole (123, 221, 1237, 6551 finiscono nell'ordine di secondi o minuti). La modifica ifdell'istruzione per if j<=i and <k<2*nvelocizzarla di più, al costo di altri 9 byte. Ho lasciato fuori divisione ( /), perché non riesco a vedere come sarebbe necessario.


Suggerimento: è necessaria la divisione.
Leaky Nun,
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.