Catena di aggiunta più corta


23

Una catena di addizione è una sequenza di numeri interi che iniziano con 1, dove ogni numero intero diverso da 1 iniziale è una somma di due numeri interi precedenti.

Ad esempio, ecco una catena di addizioni:

[1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

Ecco le somme che ne fanno una catena aggiuntiva:

1 + 1 = 2
1 + 2 = 3
1 + 3 = 4
3 + 4 = 7
1 + 7 = 8
8 + 8 = 16
16 + 16 = 32
7 + 32 = 39
32 + 39 = 71

In questa sfida, ti verrà dato un numero intero positivo ne dovrai generare una delle catene di addizione più brevi che termina n.

Esempi: nota che ci sono molti output possibili, tutto ciò che devi trovare è una catena di addizione altrettanto breve:

1: [1]
2: [1, 2]
3: [1, 2, 3]
4: [1, 2, 4]
5: [1, 2, 3, 5]
6: [1, 2, 3, 6]
7: [1, 2, 3, 4, 7]
11: [1, 2, 3, 4, 7, 11]
15: [1, 2, 3, 5, 10, 15]
19: [1, 2, 3, 4, 8, 11, 19]
29: [1, 2, 3, 4, 7, 11, 18, 29]
47: [1, 2, 3, 4, 7, 10, 20, 27, 47]
71: [1, 2, 3, 4, 7, 8, 16, 32, 39, 71]

Regole di I / O standard, ecc. Scappatoie standard vietate. Codice golf: vince il minor numero di byte.




1
Siamo autorizzati a produrre la catena in ordine inverso?
Arnauld,

@Arnauld No, questo ordine specifico.
isaacg,

Risposte:


6

Haskell , 57 byte

c=[1]:[x++[a+b]|x<-c,a<-x,b<-x]
f n=[x|x<-c,last x==n]!!0

Una soluzione di forza bruta. Provalo online!

Spiegazione

L'elenco infinito ccontiene tutte le catene di addizione, ordinate per lunghezza. È definito induttivamente in termini di se stesso, prendendo un elenco xda ce due elementi da xe aggiungendo la loro somma a x. La funzione ftrova il primo elenco cche termina con il numero desiderato.

c=            -- c is the list of lists
 [1]:         -- containing [1] and
 [x           -- each list x
  ++[a+b]     -- extended with a+b
 |x<-c,       -- where x is drawn from c,
  a<-x,       -- a is drawn from x and
  b<-x]       -- b is drawn from x.
f n=          -- f on input n is:
 [x           -- take list of those lists x
 |x<-c,       -- where x is drawn from c and
  last x==n]  -- x ends with n,
 !!0          -- return its first element.

4

Brachylog , 14 byte

∧≜;1{j⊇Ċ+}ᵃ⁽?∋

Provalo online!

Una sottomissione a forza bruta che costruisce tutte le possibili catene addizionali usando l'approfondimento iterativo, fermandosi quando viene trovata una catena contenente il suo giusto argomento. Diversamente dalla maggior parte degli invii di Brachylog, si tratta di un invio di funzioni che immette tramite il suo argomento destro (convenzionalmente chiamato Output) e genera tramite il suo argomento sinistro (convenzionalmente chiamato Input); farlo è alquanto controverso, ma la meta risposta più votata sull'argomento dice che è legale (e farlo è coerente con le nostre normali impostazioni di I / O per le funzioni). Se utilizzassimo l'input e l'output in un modo più convenzionale, questo sarebbe di 16 byte (∧≜;1{j⊇Ċ+}ᵃ⁽.∋?∧), in quanto il lato destro del programma non sarebbe in grado di utilizzare il vincolo implicito (pertanto richiederebbe tale disabilitazione e un nuovo vincolo esplicito, al costo di 2 byte).

Spiegazione

∧≜;1{j⊇Ċ+}ᵃ⁽?∋
∧               Disable implicit constraint to read the left argument
 ≜;        ⁽    Evaluation order hint: minimize number of iterations
    {    }ᵃ     Repeatedly run the following:
   1      ᵃ       From {1 on the first iteration, results seen so far otherwise}
     j            Make {two} copies of each list element
      ⊇           Find a subset of the elements
       Ċ          which has size 2
        +         and which sums to {the new result for the next iteration}
             ∋    If the list of results seen so far contains {the right argument}
            ?     Output it via the left argument {then terminate}

Una sottigliezza interessante qui è ciò che accade nella prima iterazione, in cui l'input è un numero anziché un elenco come nelle altre iterazioni; iniziamo con il numero 1, facciamo due copie di ogni cifra (creando il numero 11), quindi troviamo una sottosequenza di 2 cifre (anche il numero 11). Quindi prendiamo la somma delle sue cifre, che è 2, e come tale la sequenza inizia [1,2]come vogliamo. Su iterazioni future, stiamo iniziando con una lista come [1,2], raddoppiando a [1,2,1,2], poi prendere una a due elementi sottosequenza ( [1,1], [1,2], [2,1], o [2,2]); chiaramente, le somme di ciascuno di questi saranno i prossimi elementi validi della catena di addizione.

È un po 'frustrante qui che qui sia necessario il suggerimento dell'ordine di valutazione, in particolare il componente (sembra che per impostazione predefinita prenda il suggerimento dell'ordine di valutazione dall'interno anziché dall'esterno, quindi l'uso piuttosto grezzo per forzare il problema).


Avevo provato per circa 30 minuti a trovare un modo breve per fare questa sfida. La mia soluzione è stata molto più lunga di questa.
Fatalizza

1
@Fatalize: è uno di quei builtin che raramente si presentano, ma quando ne hai bisogno, ne hai davvero bisogno, poiché non esiste un modo remoto remoto per implementarlo usando altri costrutti di controllo. Quando ho capito che si trattava di una sfida, il resto è arrivato abbastanza direttamente da lì.

2

Gelatina , 17 byte

’ŒP;€µ+þ;1Fḟ@µÐḟḢ

Emette la prima soluzione lessicografa in tempo esponenziale.

Provalo online!

Come funziona

’ŒP;€µ+þ;1Fḟ@µÐḟḢ  Main link. Argument: n (integer)

’                  Decrement; n-1.
 ŒP                Powerset; generate all subarrays of [1, ..., n-1], sorted first
                   by length, then lexicographically.
   ;€              Append n to all generate subarrays.
     µ       µÐḟ   Filterfalse; keep only subarrays for which the chain between the
                   two chain separators (µ) returns a falsy value.
     µ             Monadic chain. Argument: A (array of integers)
      +þ               Add table; compute the sums of all pairs of elements in x,
                       grouping the results by the right addend.
        ;1             Append 1 to the resulting 2D array.
          F            Flatten the result.
           ḟ@          Filterfalse swapped; remove all elements of A that appear in
                       the result. This yields an empty list for addition chains.
                Ḣ  Head; select the first result.

2

JavaScript (ES6), 83 86 byte

Modifica: risolto per generare l'elenco in ordine non inverso

n=>(g=(s,a=[1])=>s-n?s>n||a.map(v=>g(v+=s,a.concat(v))):r=1/r|r[a.length]?a:r)(r=1)&&r

dimostrazione


2

PHP, 195 byte

function p($a){global$argn,$r;if(!$r||$a<$r)if(end($a)==$argn)$r=$a;else foreach($a as$x)foreach($a as$y)in_array($w=$x+$y,$a)||$w>$argn||$w<=max($a)?:p(array_merge($a,[$w]));}p([1]);print_r($r);

Provalo online!


Purtroppo questo algoritmo non fornisce risposte ottimali, ad esempio per 15.
Neil

@Neil ora è più lungo ma funziona. Non ho idea al momento come decidere quale di entrambi i modi è quello giusto. Forse il conteggio dei numeri primi ha un ruolo
Jörg Hülsermann,

questo codice non supera il test 149. La lunghezza dovrebbe essere 10, non 11
J42161217

@Jenny_mathy Corrected
Jörg Hülsermann

1

Mathematica, 140 byte

t={};s={1};(Do[While[Last@s!=#,s={1};While[Last@s<#,AppendTo[s,RandomChoice@s+Last@s]]];t~AppendTo~s;s={1},10^4];First@SortBy[t,Length@#&])&

.

produce una catena di addizione più corta diversa ogni volta che la esegui

Provalo online
incolla il codice con ctrl + v, inserisci input cioè [71] alla fine del codice e premi maiusc + invio


Dato che non ho accesso a Mathematica, che lunghezza di catena fornisce per un input di 15?
Neil,

quello giusto {1, 2, 3, 5, 10, 15}
J42161217

3
Per l'ingresso 149, ho ottenuto una catena di lunghezza 11 dal tuo programma, ma ne esiste una di lunghezza 10 ( [1,2,4,5,9,18,36,72,77,149]). Sembra che il tuo programma usi un campionamento casuale e non è garantito per trovare la soluzione ottimale.
Zgarb,

fisso! ma ci vuole più tempo
J42161217

1

Pyth, 13 byte

h-DsM^N2/#QyS

Suite di test

Fornisce la prima catena più corta dal punto di vista lessicografico. È abbastanza lento, ma non così male - si 19completa in circa 30 secondi usando pypy.

Alcune idee dalla soluzione di @ Dennis.

Mi piace molto questo - ci sono un sacco di trucchi accurati coinvolti.

Spiegazione:

h-DsM^N2/#QyS
h-DsM^N2/#QySQ    Implicit variable introduction
            SQ    Inclusive range, 1 to input.
           y      Subsets - all subsets of the input, sorted by length then lexicographically
                  Only sorted subsets will be generated.
                  Our addition chain will be one of these.
        /#Q       Filter for presence of the input.
  D               Order by
 -                What's left after we remove
     ^N2          All pairs of numbers in the input
   sM             Summed
h                 Output the list that got sorted to the front.

Questo è ancora un po 'difficile da capire, ma lasciami provare a spiegare un po' più in dettaglio.

Iniziamo con ySQ, che fornisce tutti i possibili sottoinsiemi ordinati [1, 2, ... Q], in ordine crescente di dimensioni. La catena di addizione più corta è sicuramente una di queste, ma dobbiamo trovarla.

La prima cosa che faremo è filtrare l'elenco per mantenere solo gli elenchi che contengono un Q. Lo facciamo con /#Q.

Successivamente, ordiniamo l'elenco in base a ciò che resta dopo aver rimosso il risultato di una determinata funzione. -Dordini dal resto dopo aver rimosso qualcosa.

La cosa che rimuoviamo è sM^N2, dov'è Nla lista da cui stiamo rimuovendo le cose. ^N2dà al prodotto cartesiano di Nse stesso tutte le possibili coppie di due elementi dentro N. sMquindi somma ciascuna delle coppie.

Qual è il risultato più piccolo possibile, dopo aver effettuato questa rimozione? Bene, l'elemento più piccolo nell'elenco di input rimarrà sicuramente, perché tutti i numeri sono positivi, quindi qualsiasi somma di due numeri sarà maggiore del numero più piccolo. E ci sarà almeno un numero, perché abbiamo verificato che l'input fosse presente nell'elenco. Pertanto, il risultato più piccolo possibile sarà quando ogni numero tranne il numero più piccolo è la somma di altri due numeri nell'elenco e il numero più piccolo nell'elenco è 1. In questo caso, sarà la chiave di ordinamento [1]. Questi requisiti indicano che l'elenco deve essere una catena di addizioni.

Quindi, ordiniamo le catene di addizione in primo piano. Ricorda che yfornisce i suoi sottoinsiemi in ordine crescente di dimensioni, quindi l'elenco che viene ordinato in primo piano deve essere una delle catene di addizioni più brevi. hseleziona quell'elenco.

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.