Lo strano ordinamento di Sharkovskii


35

introduzione

In questa sfida, ci occuperemo di un certo ordinamento degli interi positivi. L'ordinamento va così:

   3,    5,    7,    9,    11, ...
 2*3,  2*5,  2*7,  2*9,  2*11, ...
 4*3,  4*5,  4*7,  4*9,  4*11, ...
 8*3,  8*5,  8*7,  8*9,  8*11, ...
16*3, 16*5, 16*7, 16*9, 16*11, ...
 ...
... 64, 32, 16, 8, 4, 2, 1

Elenchiamo prima tutti gli interi dispari maggiori di 1 in ordine crescente. Quindi elenchiamo numeri dispari due volte maggiori di 1, quindi 4 volte, quindi 8 volte e così via: per tutti i k , elenchiamo 2 k volte i numeri dispari maggiori di 1 in ordine crescente. Infine, elenchiamo i poteri di due in ordine decrescente , terminando a 1. Ogni numero intero positivo si presenta in questo "elenco" esattamente una volta.

Più esplicitamente, considerare due interi positivi distinti A = n · 2 p e B = m · 2 q , dove n, m ≥ 1 sono dispari e p, q ≥ 0 . Quindi A viene prima di B nell'ordinamento, se sussiste una delle seguenti condizioni:

  • n> 1 , m> 1 e p <q
  • 1 <n <m e p = q
  • n> m = 1
  • n = m = 1 e p> q

Questo ordinamento appare nel sorprendente risultato matematico noto come teorema di Sharkovskii , che riguarda i punti periodici dei sistemi dinamici. Non entrerò nei dettagli qui.

L'obiettivo

Il tuo compito in questa sfida è calcolare l'ordine sopra indicato. I tuoi input sono due numeri interi positivi A e B , che possono essere uguali. L'output è un valore veritiero se A precede B nell'ordinamento e un valore falso in caso contrario. Se A = B , l'output dovrebbe essere veritiero. Puoi prendere A e B in entrambi gli ordini, purché tu sia coerente.

Non devi preoccuparti dell'overflow di numeri interi, ma il tuo algoritmo dovrebbe teoricamente funzionare con input arbitrariamente grandi.

Casi test

Istanze sincere

3 11
9 6
48 112
49 112
158 158
36 24
14 28
144 32
32 32
32 8
3 1
1 1

Casi falsi

1 2
1 5
11 5
20 25
2 8
256 255
256 257
72 52
2176 1216
2176 2496

Risposte:


6

JavaScript (ES6), 53 49 byte

f=(a,b)=>b<2||a>1&&(a&b&1?a<=b:a&1|~b&f(a/2,b/2))

Spiegazione:

  • Se b è 1, allora a precede (o è uguale a) b
  • Altrimenti, se a è 1, allora a non precede b
  • Altrimenti, se sia aeb sono dispari, utilizzare il controllo regolare della disuguaglianza
  • Altrimenti, se a è dispari, allora precede b
  • Altrimenti, se b è dispari, allora a non precede b
  • Altrimenti, dividi sia a che b per 2 e riprova.

Modifica: salvato 2 byte grazie a @Arnauld.


Bello. Non ho pensato di usare la ricorsione qui. Funzionerebbe a&1|~b&1&f(a/2,b/2)?
Arnauld,

@Arnauld Non ne sono sicuro, ero preoccupato che si sarebbe chiuso a ciclo indefinito.
Neil,

Non può, perché b<2alla fine sarà vero. Ora, un altro problema è che elaborerai più iterazioni del necessario e otterrai valori in virgola mobile. Ma non riesco a trovare alcun controesempio che non funzionerebbe come previsto.
Arnauld,

@Arnauld Ah, giusto, non stavo usando b<2originariamente, ma suppongo che ora funzionerà.
Neil,

@Arnauld Meglio ancora, dal momento che f(a/2,b/2)solo i rendimenti 0, 1, falseo true, non ho nemmeno bisogno del &1.
Neil,

6

Python 2, 50 byte

lambda*l:cmp(*[([-n][n&n-1:],n&-n,n)for n in l])<1

Ogni numero è mappato su una tripla il cui ordine ordinato è l'ordine desiderato.

  • Il valore principale è [-n][n&n-1:], che gestisce i poteri di 2 alla fine. Il bit per bit "e" n&n-1è zero esattamente quando nè un potere di 2. In tal caso, otteniamo l'elenco [-n], e altrimenti l'elenco vuoto []. Questo mette tutti i poteri di 2 alla fine dell'ordine, in ordine decrescente.
  • Il valore secondario n&-nestrae il fattore di potenza di 2 di n.
  • Il valore finale npareggi pari a 2 potenze a favore del numero maggiore.

Le rispettive tuple vengono passate cmpper vedere se quel confronto è <=0. Python 3 salverebbe un byte con divisione float (n&n-1<1)/nper il primo valore nel triplo, ma manca cmp.


Non è cmp(...)<=0equivalente a cmp(...)<1?
Mathmandan,

@mathmandan Sì :)
xnor

Penso che sia lecito prendere gli interi in ordine inverso e usarli al ~posto di<1
Mitch Schwartz

5

Python 2, 87 71 byte

k=lambda n:[n&~-n<1,(n&-n)*cmp(n&~-n,1),n/(n&-n)]
lambda a,b:k(a)<=k(b)

Questo probabilmente non vincerà premi di nessuna dimensione, ma questa risposta funziona costruendo una 3-tupla usando 3 espressioni da un numero intero che, se ordinato lessicograficamente, porterà all'ordinamento corretto.

In termini leggibili, la tupla è per A = n · 2 p :

[n == 0, p * (1 - 2*(n == 0)), n]

4

JavaScript (ES6), 70 64 byte

Probabilmente si potrebbe giocare ancora un po 'a golf, ma come primo tentativo:

x=>y=>(a=x&-x,x/=a,b=y&-y,y/=b,y<2?x>1|b<=a:x>1&(b>a|b==a&y>=x))

Riceve input con la sintassi del curry (x)(y). Restituisce 0/ 1.

Casi test


Puoi estrarre le parentesi intorno e all'interno b>a||(b==a&&y>=x), non farà differenza per l'esecuzione.
XavCo7,

@ XavCo7 Va bene rimuovere le parentesi all'interno ma non intorno. Tutti i casi di test esistenti passerebbero comunque, ma un input come [1, 5]verrebbe erroneamente identificato come verità.
Arnauld,

1
@Arnauld Lo aggiungerò come nuovo test case per il futuro.
Zgarb,

3

Perl 6 , 89 84 byte

->\a,\b{my \u=*>max a,b;a==first a|b,flat [1,2,4...u].&{(3*$_,5*$_...u for $_),.reverse}}

{my \u=*>@_.max;@_[0]==first @_.any,flat [1,2,4...u].&{.map(*X*(3,5...u)),.reverse}}

( Provalo online. )

Non esattamente breve, ma ho pensato che sarebbe interessante scrivere una soluzione che in realtà generi la sequenza di ordinamento (fino a un limite superiore sicuro per ogni sotto-sequenza), e quindi controlla quale input appare prima in essa.

Per esempio:

  • Per input 2, 3genera:

    3 5
    6
    12
    4 2 1
    ... e poi osserva che 3appare prima 2.

  • Per input 9, 6genera:

    3 5 7 9 11
    6 10
    12
    24
    48
    16 8 4 2 1
    ... e poi osserva che 9appare prima 6.

Potrebbe essere più intelligente e generare anche meno della sequenza, ma ciò richiederebbe più byte di codice.


2

Python 2, 54 byte

f=lambda a,b:b<2or[f(a/2,b/2),a>1,0,1<a<=b][a%2+b%2*2]

Una soluzione ricorsiva simile a quella di Neil.


Questo sembra incasinare alcuni casi di test. Dice che f(158,158)è falso ed f(2,8)è vero.
xnor

@xnor Oops, ora dovrebbe essere risolto.
orlp

Questo dice che f(1,5)è falso.
xnor

Mio male, intendevo che f(1,5)dovrebbe essere False, ma il codice dà True.
xnor

@xnor Ah, ho individuato il bug, risolto ora (per bene spero). Ho seguito la descrizione di Neil un po 'troppo vagamente.
orlp,

1

Mathematica, 65 byte

OrderedQ[{1,#}&/@#//.{a_,b_/;EvenQ@b}->{2a,b/2}/.{a_,1}->{∞,-a}]&

Funzione senza nome che prende un elenco di numeri interi positivi e ritorna Truese l'elenco forma una sequenza crescente nell'ordine di Sharkovskii, Falsealtrimenti. (In particolare, l'elenco di input non deve contenere solo due elementi: otteniamo gratuitamente la funzionalità aggiunta.)

Il cuore dell'algoritmo è la funzione {1,#}&/@#//.{a_,b_/;EvenQ@b}->{2a,b/2}, che sposta ripetutamente i fattori di 2 in giro per convertire un numero intero del modulo m*2^k, conm dispari, nella coppia ordinata {2^k,m}(e lo fa in ogni elemento dell'elenco di input). OrderedQdecide quindi se l'elenco risultante delle coppie ordinate è già ordinato; per impostazione predefinita, ciò significa aumentare l'ordine del primo elemento, quindi aumentare l'ordine del secondo elemento.

Questo è esattamente ciò che vogliamo, tranne i numeri che sono potenze di 2 seguono regole diverse. Quindi, prima di fare il check in con OrderingQ, applichiamo un'ultima regola /.{a_,1}->{∞,-a}, che converte (per esempio) {64,1}in {∞,-64}; che mette i poteri di 2 nel posto giusto nell'ordinamento.


1

APL (Dyalog Extended) , 27 byte

1⊃∘⍋⍮⍥{p⍵⍮⍨-⍵⍴⍨⍵=2*p←⊥⍨~⊤⍵}

Provalo online!

Una funzione diadica tacita il cui argomento sinistro è a e quello di destra è b.

L'approccio è quasi identico a soluzione Python 2 xnor , in quanto convertiamo ogni numero in un array nidificato e facciamo un confronto lessicografico tra di loro.

Parte 1: Convertire il numero in array nidificato

{p⍵⍮⍨-⍵⍴⍨⍵=2*p←⊥⍨~⊤⍵}   Input: positive integer N
                  ⊤⍵    Convert N to binary digits
                 ~      Flip all the bits (1 to 0, 0 to 1)
             p←⊥⍨       Count trailing ones and assign it to p
                        (maximum power of 2 that divides N)
         ⍵=2*           Test if N itself is equal to 2^p
     -⍵⍴⍨               If true, create 1-element array containing -N;
                        otherwise, an empty array
 p⍵⍮⍨                   Form a 2-element nested array;
                        1st element is the above, 2nd is [p, N]

Parte 2: confronta due array nidificati

1⊃∘⍋⍮⍥f   Input: A (left) and B (right)
     f   Evaluate f A and f B
         Create a 2-element nested array [f A, f B]
         Grade up; indexes of array elements to make it sorted
          Here, the result is [0 1] if A  B, [1 0] otherwise
1⊃∘       Take the element at index 1 (0-based)

La sintassi di dfn supporta istruzioni condizionali, ad esempio {a:x ⋄ b:y ⋄ z}significato if a then x else if b then y else z, ma in questo caso è troppo prolisso da usare.


0

Haskell, 143 138 byte

Fondamentalmente un'implementazione relativamente semplice dei criteri:

e n=head[k-1|k<-[0..],n`mod`(2^k)>0]   -- exponent of 2
f n=n`div`2^e n                        -- odd part
a#b|n<-f a,p<-e a,m<-f b,q<-e b=n>1&&(m>1&&p<q||n<m&&p==q||m<2)||n<2&&m<2&&p>q||a==b  

Provalo online!


0

Python, 159 158 153 144 142 141 byte

Salvato un 2 byte grazie a Kritixi Lithos!

Questo è principalmente solo per praticare il golf con il mio Python!
Ha usato la formula fornita dall'OP piuttosto che i modi di tutte le risposte più intelligenti

f=lambda a,p=0:(a&1)*(a,p)or f(a>>1,p+1)
t=lambda(n,p),(m,q):(n==1)*(m==1)&(p>=q)or (m>1)&(p<=q)|(n<=m)&(p==q)or m==1
lambda a,b:t(f(a),f(b))

Puoi giocare a golf rimuovendo gli spazi non necessari: ad esempio nella (a, b)seconda riga dove puoi rimuovere lo spazio tra la virgola e b.
Kritixi Lithos,

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.