Rappresentazione più breve di un numero di sottocarico


13

Sapore

Lo stack-based Tarantopedia sottocarico ha alcuni legami interessanti per la programmazione funzionale. Uno di questi è il suo trattamento del tipo di dati numerico - come il calcolo lambda, tu rappresenti il ​​numero naturale N con una funzione che esegue un'azione N volte.

Per semplificare le cose, considereremo solo il seguente sottoinsieme di comandi Underload:

  • : - Questo comando duplica l'elemento in cima alla pila.
  • * - Questo comando concatena i primi due oggetti in pila in un singolo oggetto.

Definiamo un numero di sottocarico N come una stringa di :e *che, una volta eseguito, consuma l'articolo in cima alla pila e produce N copie di quell'elemento concatenate insieme. Qualche esempio:

  • Non ci sono numeri di sottocarico 0, -1, 1/2, π.
  • La stringa vuota è il numero 1 di sottocarico, poiché non viene toccato lo stack.
  • :*è il numero Underload 2, perché duplica l'elemento in cima e quindi concatena le due copie insieme in un singolo elemento: (A):*= (A)(A)*= (AA).
  • ::**è il numero di sottocarico 3: (A)::**= (A)(A):**= (A)(AA)*= (AAA).
  • :::*** è il numero di sottocarico 4.
  • :*:*è anche il numero di sottocarico 4: (A):*:*= (AA):*= (AA)(AA)*= (AAAA).

In generale, scoprirai che, se Me Nsono i numeri Underload M e N, allora :N*è il numero N + 1 ed MNè il numero M × N.

La sfida

Il tuo compito è quello di scrivere il programma più breve (prendendo input su STDIN) o la funzione (prendendo input tramite argomento) che produce la rappresentazione più breve del numero Underload per il suo input come stringa. Vale a dire, se l'input è un numero naturale positivo N> 1, è necessario produrre un numero N di sottocarico la cui lunghezza in caratteri è inferiore o uguale a quella di ogni altro numero di sottocarico N.

Ingressi e uscite di esempio: ("Ingresso - OUTPUT.")

  • 1 - .
  • 2 - :*.
  • 5 - ::*:**(2 × 2 + 1).
  • 7 - ::*::***(2 × 3 + 1) o :::**:**(3 × 2 + 1).
  • 33 - ::*:*:*:*:**(2 × 2 × 2 × 2 × 2 + 1).
  • 49 - ::*:*:*:*::***(16 × 3 + 1, lunghezza 14) ma non ::*::***::*::***(7 × 7, lunghezza 16).

Se l'input non è un numero naturale positivo, si è liberi di restituire un errore, produrre un comportamento indefinito o addirittura non riuscire a terminare. È apprezzata una spiegazione del metodo di presentazione della risposta per trovare la risposta.

Si applicano restrizioni standard sulle scappatoie: nessun input aggiuntivo, nessuna richiesta Web, valore di output / return deve essere esattamente la risposta e non un flusso casuale infinito di :e *, ecc.


@Geobits Non ho detto nulla sui tempi di esecuzione, quindi finché puoi dimostrare che alla fine darai la risposta corretta, sei bravo.
algoritmo

2
Questo problema riguarda le catene di addizione; in particolare, la lunghezza della risposta corretta per l'input xè 2*A117498(x)dove A117498 fornisce la combinazione ottimale di metodi binari e di fattori per trovare una catena di addizione.
Peter Taylor,

Risposte:


4

GolfScript ( 61 60 55 54 53 caratteri)

~:X'']({:A{.'.+'\*A{2$+}%~}%}*{,}${1\~X=}?{44/'*:'=}%

Questo è meno complicato rispetto alla mia versione precedente e ha un approccio leggermente diverso, ma è ancora forza bruta. Sappiamo che ':'X*'*'X*+è una soluzione candidata, quindi se generiamo tutte le stringhe ben bilanciate fino a quella lunghezza e prendiamo quella più breve che valuta la cosa giusta, possiamo essere certi di trovarne una.

# Evaluate input and store the target number in X
~:X
# Seed the generator with the empty string
'']
# X times...
({
    # Store the array of strings so far into A
    :A
    # Generate A' by mapping each element
    {
        # Dup: this leaves an untouched copy of the current string
        .
        # Wrap the duplicate in .+
        '.+'\*
        # For each element in A, generate that element suffixed with the current string
        A{2$+}%~
    }%
}*
# Order by length
{,}$
# Find the first element which evaluates to X
{1\~X=}?
# tr .+ :*
{44/'*:'=}%

Grazie a Howard, dalla cui soluzione ho rubato un paio di modifiche a 1 carattere.


Haha, un input di 3 richiede più di tre secondi per essere eseguito sull'interprete web. Giocare a golf al suo meglio.
algoritmo

@algorithmshark, puoi velocizzarlo un po 'con un po' di deduplicazione. Inserisci .&subito dopo l'anello interno (cioè tra ~}%e }*.
Peter Taylor,

4

GolfScript ( 54 53 caratteri)

Questo è un approccio che è nello spirito di Howard (costruisci stringhe che valutano il valore corretto e selezionano la forza più breve, piuttosto che bruta attraverso stringhe candidate per trovare quelle che valutano il valore corretto), ma è sufficientemente diverso da quello che penso appartiene a una risposta separata.

~.''':*':s@,{):x,2>{:^~$x^/~$+{s\*}x^%*}%{,}$0=}/]((=

Demo online non disponibile perché esegue una versione con errori dell'interprete.

# Let <N> denote the string which evaluates to N
# We want to enter the main loop with three values on the stack: <0> <1> <2>
# However, we'll never use <0>, so we can actually replace that with any value at all.
# Getting the input from underneath 3 items would normally use two stack manipulations.
# Trick: let's use the input value for <0>! (This gives a further bonus later).
# NB We store the value of <2> in the variable s
~.''':*':s@
# for x=1 to input_value ...
,{):x
    # for ^=2 to x-1 ...
    ,2>{:^
        # Use negative stack offsets to index the stack from the start
        # I.e. -1$ gets the first item on the stack, which is <0>
        # -2$ gets the second item on the stack, which is <1>
        # In general, val~$ gets <val>
        ~$x^/~$+
        # We have the string <^><x / ^> on the stack.
        # Increment it (x % ^) times to get a candidate <x>.
        {s\*}x^%*
    }%
    # Select a shortest string.
    {,}$0=
}/
# Group the stack into one array and select the appropriate offset,
# reusing that hacky <0> substitute for the offset.
]((=

Sarebbe possibile raderne uno sostituendolo 3+con )(sfruttando il fatto che []0=non lascia nulla in pila) se non lo fosse, ciò []2>porta a un errore.
Peter Taylor,

[]2>cede []senza errori.
Howard,

@Howard, ah, golfscript.apphb.com deve avere una versione precedente. Ma ho scoperto che mi sbagliavo, perché quella sostituzione porta a ottenere l'output errato per l'input '1'.
Peter Taylor,

Con cui è possibile risolvere ((=anziché -1=.
Howard,

E golfscript.apphb.com esegue effettivamente una versione precedente, l' esempio di cicli nidificati non funziona.
Howard,

4

Python 2.7 - 87 84 92

u=lambda n:n>1and min([u(i)+u(n/i)for i in range(2,n)if n%i<1]+[':'+u(n-1)+'*'],key=len)or''

Spiegazione:
Questa è una soluzione piuttosto semplice. Verifica ricorsivamente tutte le possibili rappresentazioni di n come prodotto di due numeri o come :(n-1)*, quindi trova la soluzione di lunghezza minima. l'intervallo (2, n) è necessario affinché la ricorsione abbia una profondità limitata e n <2 dia il caso base.

Appunti:
i e n / i sono i due fattori di n. Il ... e ... o ... sostituto di ... if ... else ... non funziona perché "" viene valutato come falso. min di stringhe fornisce una delle stringhe più brevi. Python 2.7 salva 1 carattere usando / invece di //.

Modifica: sposta il caso base sul retro dell'espressione, permettendomi di usare ... e ... o ... e radere un paio di spazi.

Casi test:

u(1)
''
u(5)
'::*:**'
u(49)
'::*:*:*:*::***'

1
" min di stringhe fornisce una delle stringhe più brevi " non è vero a meno che non si fornisca l'argomento facoltativo key=len. Fornisce la stringa lessicograficamente più antica. ( Esempio ). Dal momento che '*' < ':'questo significa che hai una propensione verso soluzioni che coinvolgono poteri di 2, ma sono sempre i più brevi?
Peter Taylor,

1
Risposta: in realtà il pregiudizio è più complicato, ma non sempre fornisce la risposta corretta. Il più piccolo controesempio è u(33), per il quale l'ordinamento lessicografico dà il 14 caratteri, ::**::*::*:***ma l'ordinamento per lunghezza dà il 12 caratteri::*:*:*:*:**
Peter Taylor,

1
Non l'ho mai saputo dei confronti delle stringhe Python. Ho aggiornato la mia risposta.
isaacg,

3

GolfScript, 63 58 56 caratteri

~n./\{:v~[':*'1$*v,,2>{v,\%!},{.v=v,@/v=+}/]{,}$0=]}*-2=

Il codice accetta input su STDIN e stampa il risultato.

Esempi:

> 49
:::**:*:*:*:**

> 1234
::::*:*:*:**:*:*:**::**::***

Puoi testare i tuoi casi online .


Wow, ho pensato che un approccio basato sul factoring sarebbe stato un po 'più lungo di un approccio a forza bruta.
Peter Taylor,

@PeterTaylor L'ho pensato anch'io, ma si è scoperto che non è così. Inoltre, la mia soluzione di forza bruta era un po 'più lunga della tua ;-)
Howard,

Ti dispiacerebbe spiegare cosa fa ogni porzione? Posso solo dare seguito fino al momento :x(=. Inoltre, +1 per poter eseguire 49 in un ragionevole lasso di tempo.
algoritmo

@algorithmshark Sto ancora lavorando alla soluzione, quindi potrebbe ancora cambiare molto (come appena fatto). Principalmente, la parte x,2>{x\%!},fornisce tutti i veri divisori di x, {.v=x@/v=+}/quindi concatena le soluzioni per de x/dper tutti i divisori d. {,}$li ordina per lunghezza e ne 0=prende il più breve (più il :(x-1)*caso iniziale ).
Howard,

2

Brachylog 2 , 30 (forse 26) byte, lingua post-data sfida

Ecco una funzione che funziona con l'attuale implementazione di Brachylog 2 (e restituisce un elenco di codici carattere poiché l'implementazione corrente presenta alcuni problemi con la gestione delle stringhe):

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}

Provalo online!

La lingua è ancora molto nuova. Ecco una versione del programma da 26 byte che dovrebbe funzionare secondo le specifiche, ma utilizza alcune funzionalità non implementate e quindi non è ancora valida, ma forse lo sarà in futuro (è anche meno efficiente):

{ḋp~c×ᵐ{-₁↰₁:"*:"c↻}ᵐc}ᶠlᵒh

Spiegazione

∧.l∧?{ḋp~c×ᵐ{-₁↰₁:[42,58]c↻}ᵐc}
∧.l∧?                            Evaluation hint: try shortest outputs first
     {                        }  Define an inner function
      ḋ                          Prime factor decomposition of the input
       p                         Find a permutation
        ~c                       Find an inverse concatenation (i.e. partition)
          ×ᵐ                     Take the product of each set inside the partition
      ḋp~c×ᵐ                     Find a decomposition into factors ≥ 2
            {              }ᵐ    For each of those factors:
             -₁                  Decrement it
               ↰₁                Call the inner function recursively
                 :[42,58]c       Append "*:" (as character codes)
                          ↻      Move the last element to the start
                             c   Append the results together

L'idea di base è abbastanza semplice: alterniamo la scomposizione del numero in (1 o più) fattori (non necessariamente i fattori primi, ma i fattori 1 non sono ammessi) e l'espressione di ciascuno di questi come 1 + (una rappresentazione ottenuta da un metodo ricorsivo chiamata). Questo è garantito per cercare tutte le possibili rappresentazioni del numero di sottocarico (possiamo applicare uno stadio di moltiplicazione "due volte di fila" moltiplicando insieme più di 2 numeri e uno stadio di incremento due volte di fila separandoli con uno stadio di moltiplicazione che si moltiplica insieme solo un numero). Non abbiamo bisogno di un caso base esplicito, perché la scomposizione di 1 in fattori primi ci dà un elenco vuoto, e quindi lo costruiamo con uno stadio di moltiplicazione che moltiplica zero numeri insieme.

Il programma è abbastanza inefficiente, soprattutto perché il suggerimento sull'ordine di valutazione che ho dato (generare risposte dal più breve al più lungo in termini di dimensioni dell'eventuale output), pur risolvendo la parte "più breve" della domanda, non è eccezionale in termini di effettivamente completare rapidamente il programma (un suggerimento molto più utile sarebbe "generare solo la risposta più breve in ogni fase ricorsiva", ma questo richiede più byte ...). Inoltre, ḋp~c×ᵐpuò generare partizioni moltiplicative più volte ciascuna, facendo sì che il programma faccia un sacco di lavoro ridondante.


0

J - 81 caratteri

Per i posteri, questo era il meglio che potevo fare in J.

_2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:

Creiamo un elenco di risultati, iniziando con due stringhe vuote (che è il ,~e a:) che rappresentano 0 (mai usato) e 1, e quindi ripetiamo un verbo su di loro (uso subdolo di hook, treni e &) che accoda la rappresentazione più breve del numero successivo.

Il verbo effettivo che ripetiamo utilizza la lunghezza dell'elenco come indicatore del numero su cui stiamo operando. Innanzitutto, calcoliamo questo numero in coppie di fattori ( #(#~]-:"1<.)@(],.%)2}.i.@#) e recuperiamo ogni coppia estraendo dall'array ( {~). Trasformiamo ciascuna di quelle coppie (potrebbero esserci 0 se il numero è primo) in stringhe singole ( <@;"1).

Quindi aggiungiamo a quell'elenco la voce per il risultato precedente racchiusa tra :e *, e ordiniamo questo elenco per lunghezza ( (/:#&>)). Infine, prendiamo il primo risultato da questo elenco ( 0{) e lo aggiungiamo alla fine dell'array di base ( [,). Al termine dell'iterazione del ciclo, abbiamo un elenco di lunghezza 2 in più rispetto all'input, che inizia da 0. Quindi ciò che dobbiamo restituire è la stringa penultima ( _2{::).

   un =: _2{::(0&(][,0{<@;"1@({~#(#~]-:"1<.)@(],.%)2}.i.@#)(/:#&>)@,':'<@,'*',~>@{:),~)&a:
   un 49
::*:*:*:*::***
   un 1234
:*::*:*:*::*::***::*::*:****
   un 10010
:*::*:*::***::*:*:*:*:*:*:*::***
   2 * (1 + 3 * 2^2) * (1 + 3 * 2^7)
10010
   6!:2 'un 10010'   NB. time in seconds
19.5539

0

Jelly , 33 byte, sfida postdatati in lingua

ÆḌḊµ⁹÷Ñ;Ñð€
’ß”:;;”*W;ÇLÞḢµ“”>1$?

Provalo online!

Una soluzione semplice per la forza bruta.

Spiegazione

Programma principale

’ß”:;;”*W;ÇLÞḢµ“”>1$?
              µ  >1$?  If input is greater than 1, then:
’ß                       Run recursively on the input - 1
  ”:;                    Prepend a colon
     ;”*                 Append an asterisk
        W;               Cons to:
          Ç                the result of the helper, on {the original input}
           LÞ            Sort by length
             Ḣ           Take the first (i.e. shortest) result
               “”      Otherwise, return an empty string

Il programma principale utilizza la funzione helper per enumerare tutti i modi possibili per produrre il valore tramite la moltiplicazione, quindi prova a produrre il valore per addizione e restituisce la possibilità più breve. Gestisce anche il case base (un input di1 ).

Funzione di aiuto

ÆḌḊµ⁹÷Ñ;Ñð€
ÆḌ µ     ð€            For all proper factors of the input
  Ḋ                    except the first (i.e. 1):
    ⁹÷                   Divide it into the input;
      Ñ                  Run the main program on it;
       ;                 Append the result of:
        Ñ                  the main program run on {the factor}

La funzione helper prova tutti i possibili metodi per esprimere l'input come una moltiplicazione di due numeri e chiama reciprocamente ricorsivamente il programma principale per ottenere le loro rappresentazioni più brevi.


0

GNU Prolog, 96 byte

v(N)-->{N#=1};{N#=A*B,A#<B,B#<N},v(A),v(B);{N#=M+1},":",v(M),"*".
s(N,S):-length(S,_),v(N,S,[]).

La prima riga è una grammatica che implementa la valutazione di sottocarico e funziona nella direzione opposta (in realtà, non funziona nella direzione in avanti a causa del A#<Bvincolo; cambiarla in A#<Nper un programma più lento che funzioni in entrambi i modi). La seconda riga definisce il predicato simile a una funziones (che è la funzione implementata come soluzione a questo programma) che trova la stringa più breve possibile che valuta il numero indicato come input (questo è frustrantemente dettagliato per ciò che è un'attività relativamente semplice, ma questo è Prolog per te ...).

Il programma dovrebbe essere piuttosto autoesplicativo, dato che si tratta più o meno di una traduzione diretta delle specifiche in una grammatica e quindi nella sintassi di Prolog; la definizione di vdice che Nè 1 in una stringa vuota, oppure Nè A× B(con Ameno di Bminore di N) e la stringa è la concatenazione di v(A)e v(B), oppure Nè M+ 1 e la stringa è :concatenata con mezzi "S ha una certa lunghezza", ma specificando questo come la prima cosa sulla linea funge da suggerimento per l'implementazione di Prolog che dovrebbe prima verificare le lunghezze più brevi (il che significa che otterremo la lunghezza più breve possibile per un valore di ritorno).v(M) concatenata con *. La seconda riga è un po 'più sottile;length(S,_)

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.