Numeri di purezza


27

Oggi vedremo una sequenza a , correlata alla funzione Collatz f :

inserisci qui la descrizione dell'immagine

Chiamiamo una sequenza della forma z, f (z), f (f (z)), ... una sequenza di Collatz .

Il primo numero nella nostra sequenza, a (1) , è 0 . Sotto ripetute applicazioni di f , rientra in un ciclo 0 → 0 →…

Il numero più piccolo che non abbiamo ancora visto è 1, facendo un (2) = 1 . Sotto ripetute applicazioni di f , rientra in un ciclo 1 → 4 → 2 → 1 → ...

Ora abbiamo visto il numero 2 nel ciclo sopra, quindi il prossimo numero più piccolo è a (3) = 3 , cadendo nel ciclo 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 → 4 → 2 → 1 → ...

In tutti i cicli precedenti abbiamo già visto 4 e 5 , quindi il numero successivo è a (4) = 6 .

Ormai dovresti avere l'idea. a (n) è il numero più piccolo che non faceva parte di alcuna sequenza di Collatz per tutte a (1), ..., a (n - 1) .

Scrivi un programma o una funzione che, dato un numero intero positivo n , restituisce a (n) . Vince il codice più breve in byte.


Casi test:

1  -> 0
2  -> 1
3  -> 3
4  -> 6
5  -> 7
6  -> 9
7  -> 12
8  -> 15
9  -> 18
10 -> 19
50 -> 114

(Questa è la sequenza OEIS A061641 .)



3
L'input può nessere basato su 0?
Luis Mendo,

a(n+1) = a(n) odd: 3*a(n)+1, or a(n) even: a(n)/2
Karl Napf,

@LuisMendo Mi dispiace, in qualche modo ho perso il tuo messaggio. No, riproduci la sequenza esatta come nella sfida.
Orlp,

Se anon è basato su 0, non capisco perché sembri "parlare di base 0" qui:a(n) is the smallest number that was not part of any Collatz sequences for all a(0), …, a(n − 1).
daniero,

Risposte:


5

Gelatina , 20 19 byte

ḟ@JḢ×3‘$HḂ?ÐĿ;Ṛ
Ç¡Ṫ

Provalo online! o verifica tutti i casi di test .

Come funziona

Ç¡Ṫ              Main link. No explicit arguments. Default argument: 0
 ¡               Read an integer n from STDIN and do the following n times.
Ç                  Call the helper link.
  Ṫ              Tail; extract the last element of the resulting array.


ḟ@JḢ×3‘$HḂ?ÐĿ;Ṛ  Helper link. Argument: A (array)

  J              Yield all 1-based indices of A, i.e., [1, ..., len(A)]. Since 0
                 belongs to A, there is at least one index that does belong to A.
ḟ@               Filter-false swapped; remove all indices that belong to A.
   Ḣ             Head; extract the first index (i) that hasn't been removed.
           ÐĿ    Call the quicklink to the left on i, then until the results are no
                 longer unique. Collect all unique results in an array.
         Ḃ?      If the last bit of the return value (r) is 1:
       $           Apply the monadic 3-link chain to the left to r.
    ×3‘              Yield 3r + 1.
        H        Else, halve r.
              Ṛ  Yield A, reversed.
             ;   Concatenate the results array with reversed A.

Dopo n iterazioni, il valore di a (n + 1) sarà all'inizio dell'array. Poiché concateniamo il nuovo array con una copia invertita di quello vecchio, ciò significa che alla fine sarà presente un (n) .


9

Haskell, 93 92 byte

c x|x<2=[[0,2]!!x]|odd x=x:c(3*x+1)|1<2=x:c(div x 2)
([y|y<-[-1..],all(/=y)$c=<<[0..y-1]]!!)

Esempio di utilizzo: ([y|y<-[-1..],all(/=y)$c=<<[0..y-1]]!!) 10-> 19.

c xè il ciclo di Collatz xcon un po 'di tradimenti per x == 1. Le funzioni principali scorre tutti gli interi e mantiene quelli che non sono in c xper xa [0..y-1]. Praticamente un'implementazione diretta della definizione. Poiché l'operatore dell'indice Haskell !!è basato su 0, inizio a -1anteporre un numero (altrimenti inutile) per ottenere l'indice corretto.


4

MATL , 46 40 byte

Oiq:"tX>Q:yX-X<`t0)to?3*Q}2/]h5M1>]Pv]0)

Provalo online!

Spiegazione

Il codice ha un forciclo esterno che genera nsequenze di Collatz, una per ogni iterazione. Ogni sequenza è generata da un do...whileciclo interno che calcola nuovi valori e li memorizza in un vettore di sequenza fino a quando non viene ottenuto un 1o 0. Quando abbiamo finito con la sequenza, il vettore viene invertito e concatenato a un vettore globale che contiene i valori di tutte le sequenze precedenti. Questo vettore può contenere valori ripetuti. L'inversione del vettore di sequenza assicura che alla fine del ciclo esterno il risultato desiderato (il valore iniziale dell'ultima sequenza) sarà alla fine del vettore globale.

Pseudo-codice :

1  Initiallization
2  Generate n sequences (for loop):
3    Compute initial value for the k-th sequence
4    Generate the k-th sequence (do...while loop)
5      Starting from latest value so far, apply the Collatz algorithm to get next value
6      Update sequence with new value 
7      Check if we are done. If so, exit loop. We have the k-th sequence
8    Update vector of seen values
9  We now have the n sequences. Get final result

Codice commentato :

O           % Push 0                                                          1
iq:         % Input n. Generate [1 2 ... n-1]                                 ·
"           % For loop: repeat n-1 times. Let k denote each iteration         2
  t         %   Duplicate vector of all seen values                           · 3
  X>Q       %   Take maximum, add 1                                           · ·
  :         %   Range from 1 to that: these are potential initial values      · ·
  y         %   Duplicate vector of all seen values                           · ·
  X-X<      %   Set difference, minimum: first value not seen                 · ·
  `         %   Do...while: this generates the k-th Collatz sequence          · 4
    t0)     %     Duplicate, push last value of the sequence so far           · · 5
    to      %     Duplicate, parity: 1 if odd, 0 if even                      · · ·
    ?       %     If odd                                                      · · ·
      3*Q   %       Times 3, plus 1                                           · · ·
    }       %     Else                                                        · · ·
      2/    %       Half                                                      · · ·
    ]       %     End if                                                      · · ·
    h       %     Concatenate new value of the sequence                       · · 6
    5M      %     Push the new value again                                    · · 7
    1>      %     Does it exceed 1? This is the loop condition                · · ·
  ]         %   End do...while. The loops ends when we have reached 0 or 1    · ·
  P         %   Reverse the k-th Collatz sequence                             · 8
  v         %   Concatenate with vector of previously seen values             · ·
]           % End for                                                         ·
0)          % Take last value. Implicitly display.                            9


3

Python 2, 97 96 byte

r,=s={-1}
exec'n=r=min({r+1,r+2,r+3}-s)\nwhile{n}-s:s|={n};n=(n/2,3*n+1)[n%2]\n'*input()
print r

Sfrutta il fatto che tutti i multipli di 3 sono puri. Provalo su Ideone .

Come funziona

Sulla prima riga, r,=s={-1}imposta s = {-1} (set) e r = -1 .

Quindi leggiamo un numero intero da STDIN, ripetiamo una determinata stringa più volte, quindi eseguiamo. Ciò equivale al seguente codice Python.

for _ in range(input())
    n=r=min({r+1,r+2,r+3}-s)
    while{n}-s:
        s|={n}
        n=(n/2,3*n+1)[n%2]

In ogni iterazione, iniziamo trovando il membro più piccolo di {r + 1, r + 2, r + 3} che non appartiene a s . Nella prima iterazione, questo inizializza r come 0 .

In tutte le sequenze successive, s può (e conterrà) alcuni di r + 1 , r + 2 e r + 3 , ma mai tutti, poiché tutti i multipli di 3 sono puri. Per verificare questa affermazione, osservare che nessuna multipla m di 3 è della forma 3k + 1 . Ciò lascia 2m come unica possibile pre-immagine, che è anche un multiplo di 3 . Pertanto, m non può apparire nella sequenza di Collatz di alcun numero inferiore a m ed è quindi puro.

Dopo aver identificato r e inizializzato n , applichiamo la funzione Collatz con n=(n/2,3*n+1)[n%2], aggiungendo ogni valore intermedio di n all'insieme s con s|={n}. Una volta che incontriamo un numero n che è già in s , {n}-sprodurrà un set vuoto e l'iterazione si interromperà.

L'ultimo valore di r è l'elemento desiderato della sequenza.


1
Per aggiungere a ciò, una prova che tutti i multipli di 3 sono puri. Guarda qualsiasi sequenza di Collatz modulo 3. Dopo qualsiasi applicazione della regola 3x + 1, il modulo è 1. Dopo l'applicazione della regola x / 2, mod 1 diventa 2 e mod 2 diventa 1. Nessuna delle due regole può generare un multiplo di 3, a meno che il valore iniziale non fosse già un multiplo più grande di 3 che è stato dimezzato. Ma quelli sono valori più grandi non ancora generati, quindi n = 0 (mod 3) => n è puro.
orlp,


1

Java, 148 byte

int a(int n){if(n<2)return 0;int f=a(n-1),b,i,c;do{f++;for(b=1,i=1;i<n;i++)for(c=i==2?4:a(i);c>1;c=c%2>0?c*3+1:c/2)b=c==f?0:b;}while(b<1);return f;}

Ideone esso! (Attenzione: complessità esponenziale dovuta a zero ottimizzazione.)

Convertirlo da un do...whileloop in un forloop sarebbe più golfista, ma ho problemi a farlo.

I consigli sul golf sono i benvenuti come al solito.


Non molto, ma puoi golf 1 byte spento cambiando for(b=1,i=1;i<n;i++)in for(b=1,i=0;++i<n;). A proposito, capisco perché al tuo ideone manca il test case per 50, ma perché manca anche il 10? Può gestirlo senza problemi.
Kevin Cruijssen,

@KevinCruijssen Perché la formattazione sarebbe sbagliata.
Leaky Nun,

Non è il miglioramento migliore, ma non ho trascorso troppo tempo ... (147 byte)int a(int n){if(n<2)return 0;int f=a(n-1),b=0,i,c;for(;b<1;){f++;for(b=1,i=1;i<n;i++)for(c=i==2?4:a(i);c>1;c=c%2>0?c*3+1:c/2)b=c==f?0:b;}return f;}
Poke

1

Perl6, 96

my @s;my $a=0;map {while ($a=@s[$a]=$a%2??3*$a+1!!$a/2)>1 {};while @s[++$a] {}},2..slurp;$a.say;

Basato sulla risposta Perl 5 . Un po 'più a lungo poiché la sintassi Perl6 è meno tollerante della sintassi Perl5, ma per ora mi accontenterò di questo.


0

PHP, 233 124 byte

<?$n=$argv[1];for($c=[];$n--;){for($v=0;in_array($v,$c);)$v++;for(;$n&&!in_array($v,$c);$v=$v&1?3*$v+1:$v/2)$c[]=$v;}echo$v;

+4 per la funzione:

function a($n){for($c=[];$n--;){for($v=0;in_array($v,$c);)$v++;for(;$n&&!in_array($v,$c);$v=$v&1?3*$v+1:$v/2)$c[]=$v;}return$v;}

0

Perl 5 - 74 byte

map{0 while 1<($a=$c[$a]=$a%2?$a*3+1:$a/2);0 while$c[++$a]}2..<>;print$a+0

Questa è una soluzione piuttosto semplice. Applica ripetutamente la funzione Collatz alla variabile $ae memorizza nell'array @cche il valore è stato visto, quindi dopo aver raggiunto 0 o 1 si incrementa $afino a quando non è ancora stato visto un numero. Questo viene ripetuto un numero di volte uguale all'ingresso meno 2 e infine $aviene emesso il valore di .


0

Mathematica, 134 byte

f=If[EvenQ@#,#/2,3#+1]&;a@n_:=(b={i=c=0};While[i++<n-1,c=First[Range@Max[#+1]~Complement~#&@b];b=b~Union~NestWhileList[f,c,f@#>c&]];c)

Formato più facile da leggere:

f = If[EvenQ@#, #/2, 3#+1] &;                        Collatz function
a@n_ := (                                            defines a(n)
  b = {i = c = 0};                                   initializations
                                                       b is the growing sequence
                                                       of cycles already completed
  While[i++ < n - 1,                                 computes a(n) recursively
    c = First[Range@Max[# + 1]~Complement~# & @b];   smallest number not in b
    b = b~Union~NestWhileList[f, c, f@# > c &]       apply f to c repeatedly
                                                       until the answer is smaller
                                                       than c, then add this new
                                                       cycle to b
    ]
  ; c)                                                 output final value of c
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.