Trova una funzione con cicli di ogni lunghezza


11

Si dice che una funzione ha un ciclo di lunghezza n se esiste una x nel suo dominio tale che f n (x) = x e f m (x) ≠ x per 0 <m <n , dove l'apice n indica n - piega l'applicazione di f . Si noti che un ciclo di lunghezza 1 è un punto fisso f (x) = x .

Il tuo compito è implementare una funzione biiettiva dagli interi a se stessi, che ha esattamente un ciclo di ogni lunghezza positiva n . Una funzione biiettiva è una corrispondenza uno a uno, ovvero ogni numero intero mappato esattamente una volta. Avere esattamente un ciclo di lunghezza n significa che ci sono esattamente n numeri distinti x per i quali f n (x) = x e f m (x) ≠ x per 0 <m <n .

Ecco un esempio di come potrebbe apparire una tale funzione attorno a x = 0 :

x     ... -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7 ...
f(x)  ...  2  4  6 -3 -1  1 -4  0 -2  5  7 -7 -6  3 -5 ...

Questo estratto contiene cicli di lunghezza da 1 a 5 :

n   cycle
1    0
2   -2  1
3   -4 -3 -1
4   -5  6  3  7
5   -7  2  5 -6  4
...

Si noti che sopra sto usando "funzione" solo in senso matematico. È possibile scrivere una funzione o un programma completo nella lingua prescelta, purché richieda un singolo numero intero (con segno) come input e restituisca un numero intero (con segno). Come al solito è possibile prendere input tramite STDIN, argomento della riga di comando, argomento della funzione ecc. E output tramite STDOUT, valore di ritorno della funzione o argomento della funzione (out) ecc.

Naturalmente, molte lingue non supportano (facilmente) numeri interi di precisione arbitraria. Va bene se l'implementazione funziona solo sull'intervallo del tipo intero nativo della tua lingua, a condizione che copra almeno l'intervallo [-127, 127] e che funzionerebbe per interi arbitrari se il tipo intero della lingua fosse sostituito con arbitrario- numeri interi di precisione.

Si applicano le regole standard del .


2
Strettamente correlato. Mentre le differenze sembrano minori, implicano che nessuno dei vecchi approcci funziona senza modifiche significative, e in particolare non penso che l'approccio vincente di quella sfida possa essere adattato affatto.
Martin Ender,

"ha esattamente un ciclo di ogni lunghezza", "ha molti cicli di ogni lunghezza": è questa l'unica differenza che distingue te dall'altro?
Abr001am

@ Agawa001 Questa è una differenza, l'altra è che l'altra sfida riguarda le funzioni sugli interi positivi, mentre questa sfida richiede una funzione su tutti gli interi.
Martin Ender,

1
Penso che la tua definizione di ciclo debba includere che n è minimo. In caso contrario, il ciclo di lunghezza 2 conta anche come ciclo di lunghezza 4 e 6 e così via.
xnor

@xnor Whoops, buon punto.
Martin Ender,

Risposte:


2

Pyth, 27 18 byte

_h?gQ0^2Q*.5@,Q-xh

Spiegazione (Pyth si inizializza sull'intero Qdi input):

_                       negative of (
                          (
  ?gQ0                      if Q >= 0:
      ^2Q                     2**Q
                            else:
         *.5                  half of
            @        Q          element Q (modulo list length) in
             ,                    the two element list [
              Q                     Q,
                 hQ                 ((Q plus 1)
                x  Q                 XOR Q)
               -    Q               minus Q
                                  ]
 h                        ) plus 1
                        )

Questo ha cicli

(−1)
(0, −2)
(1, −3, −4)
(2, −5, −7, −6)
(3, −9, −13, −11, −8)
(4, - 17, −25, −21, −15, −10)
(5, −33, −49, −41, −29, −19, −12)
(6, −65, −97, −81, −57, −37, −23, −14)
(7, −129, −193, −161, −113, −73, −45, −27, −16)
(8, −257, −385, −321, −225 , −145, −89, −53, −31, −18)
(9, −513, −769, −641, −449, −289, −177, −105, −61, −35, −20)

Il ciclo di lunghezza n è dato da

( n - 2,
−2 ^ ( n - 2) ⋅1 - 1,
−2 ^ ( n - 3) ⋅3 - 1,
−2 ^ ( n - 4) ⋅5 - 1,
…,
−2 ^ 2 ⋅ (2 · n - 7) - 1,
−2 ^ 1⋅ (2 · n - 5) - 1,
−2 ^ 0⋅ (2 · n - 3) - 1).

Ogni intero k ≥ −1 appare come primo elemento del ciclo ( k + 2). Per ogni numero intero k <−1, possiamo scrivere in modo univoco 1 - k = 2 ^ i ⋅ (2⋅ j + 1) per alcuni i , j ≥ 0; quindi k appare come ( j + 2) th elemento del ciclo ( i + j + 2).


5

MATL , 47 byte

E|G0<-QXJ:tQ*2/0hStJ<f0))Q2MQ)&:J6M-)2/ttk>Eq*k

Provalo online!

Spiegazione generale

La funzione 2 di seguito è la stessa utilizzata nella risposta di @ Sp3000 alla relativa sfida. Grazie a @ Agawa001 per averlo notato.

La funzione è la composizione di tre:

  1. Bijection da Z (gli interi) a N (i naturali).
  2. Biiezione da N a N con la caratteristica desiderata (un ciclo di ogni lunghezza).
  3. Inverso della funzione 1.

Funzioni 1 e 3 vengono utilizzati perché è più facile (Credo) per ottenere il comportamento desiderato in N rispetto a Z .

La funzione 2 è la seguente: la riga superiore è dominio, la riga inferiore è codomain. Le virgole vengono utilizzate per chiarezza:

1,  2  3,  4  5  6,  7  8  9  10  ...
1,  3  2,  6  4  5, 10  7  8   9  ...

Il primo blocco (dall'alto 1verso il basso 1) è un ciclo di lunghezza 1. Il secondo (da 2 3a 3 2) è un ciclo di lunghezza 2, ecc. In ogni blocco, la parte inferiore (immagine della funzione) è la parte superiore spostata in modo circolare un passo a destra.

La funzione 1 è la seguente:

 -5  -4  -3  -2  -1   0  +1  +2  +3  +4  ...
+10  +8  +6  +4  +2  +1  +3  +5  +7  +9  ...

La funzione 3 è uguale a 1 con le due linee scambiate.

Esempi

L'immagine di 3è -5. Il primo 3è mappato 7dalla funzione 1; quindi 7viene mappato 10dalla funzione 2; quindi 10viene mappato a -5` dalla funzione 3.

Il ciclo di lunghezza 1 è 0. Il ciclo di lunghezza 2 è -1 1. Il ciclo di lunghezza 3 è -3 2 -2, ecc.

Codice spiegato

Le funzioni 1 e 3 sono semplici.

La funzione 2 funziona trovando l'endpoint inferiore del blocco di input corrispondente. Ad esempio, se l'input per questa funzione 9trova 7(vedi i blocchi sopra). Quindi seleziona l'endpoint superiore, che è 10nell'esempio. Lo spostamento circolare del blocco è ottenuto grazie all'indicizzazione modulare su base 1 di MATL.

         % FUNCTION 1
         % Implicit input
E|       % Multiply by two. Absolute value
G0<      % 1 if input is negative, 0 otherwise
-        % Subtract
Q        % Add 1
XJ       % Copy to clipboard J. Used as input to the next function

         % FUNCTION 2
:        % Range [1 2 ... J], where J denotes the input to this function
tQ*      % Duplicate, increment by 1, multiply
2/       % Divide by 2
0hS      % Prepend a 0. This is needed in case J is 0
tJ<f     % Duplicate. Find indices that are less than the input J
0)       % Pick the last index.
)        % Apply as index to obtain input value that ends previous block
Q        % Add 1: start of current block
2M       % Push the two arguments to second-to-last function call
Q)       % Add 1 and use as index: end of current block
&:       % Inclusive binary range: generate input block 
J        % Push J (input to function 2)
6M-      % Subtract start of block
)        % Apply as index (1-based, modular). This realizes the shifting

         % FUNCTION 3
2/       % Divide by 2
ttk>     % Duplicate. 1 if decimal part is not 0; 0 otherwise
Eq       % Multiply by 2, add 1
*        % Multiply
k        % Round down
         % Implicit display

questa è una svolta della funzione sp3000 giusto?
Abr001am

@ Agawa001 Oh, vero? Non ho visto l'altra sfida. Dò un'occhiata
Luis Mendo,

Oh. Lo è sicuramente. Almeno questo chiarisce che il mio ragionamento, se non originale, era corretto :-)
Luis Mendo,

è sorprendente come più di una mente sia strettamente inquadrata per trasudare idee vicine.
Abr001am

4

Python 2, 55 byte

g=lambda n,k=1:n/k and~g(~n+k*(n>0),k+1)+k*(n>0)or-~n%k

59 byte:

g=lambda n,k=1:n<0and~g(~n,2)or n/k and k+g(n-k,k+2)or-~n%k

Crea i cicli

[0]
[-1, -2]
[1, 2, 3]
[-3, -4, -5, -6]
[4, 5, 6, 7, 8]
...

Modificato dalla mia soluzione sulla sfida precedente , che è stata modificata dalla costruzione di Sp3000 .

La funzione

g=lambda n,k=1:n/k and k+g(n-k,k+2)or-~n%k

crea cicli di dimensioni dispari di numeri non negativi

[0]
[1, 2, 3]
[4, 5, 6, 7, 8]
...

Per trovare la dimensione del ciclo corretta k, spostare l'ingresso nverso il basso k=1,3,5,7,...fino a quando il risultato non è nell'intervallo[0,k) . Ciclare questo intervallo con l'operazione n->(n+1)%k, quindi annullare tutte le sottrazioni eseguite sull'input. Questo è implementato in modo ricorsivo da k+g(n-k,k+2).

Ora, abbiamo bisogno del negativo per fare i cicli pari. Nota che se modifichiamo gper cominciare k=2a g, otterremmo cicli anche a grandezza naturale

[0, 1]
[2, 3, 4, 5]
[6, 7, 8, 9, 10, 11]
...

Questi si uniscono ai negativi tramite il complemento di bit ~. Quindi, quando nè negativo, valutiamo semplicemente g(n)come ~g(~n,2).


Non so se sia d'aiuto, ma ksembra essere un altro modo di calcolare Math.floor(Math.sqrt(n))*2+1.
Neil,

@Neil Ho cercato di determinare i limiti e le dimensioni del ciclo in modo aritmetico e anche di fare l'intero calcolo in quel modo, ma queste espressioni sono lunghe in Python e ho trovato la ricorsione più breve.
xnor

3

Python 3, 110 byte

Non ho ancora capito come ottenere un lambda lì dentro

se n è un numero triangolare [1,3,6,10,15,21,28, ecc ...] allora f (n) è l'ordine nell'elenco moltiplicato per uno negativo. se il numero è negativo, assegnagli 1 + il numero del triangolo più piccolo successivo. altrimenti, incremento.

Esempio: 5 non è un numero triangolare, quindi aggiungi 1.

La prossima iterazione, abbiamo 6. 6 è un numero di triangolo, ed è il 3 ° nella lista, quindi esce -3.

Il programma fornisce queste liste

lunghezza 1: [0]

lunghezza 2: [1, -1]

lunghezza 3: [2,3, -2]

lunghezza 4: [4,5,6, -3]

lunghezza 5: [7,8,9,10, -4]

x=int(input())
if x<0:print((x**2+x)/2+1)
else:
 a=((8*x+1)**.5-1)/2
 if a%1:print(x+1)
 else:print(-a)

Modifica: grazie ancora a @TuukkaX per aver rimosso i caratteri in eccesso.


1
Potresti cambiare 0.5in .5e input('')in input().
Yytsi,

2

Python 3, 146 byte

Per ogni numero maggiore di 0, ci sono anche loop (len 2,4,6,8 ...) e meno di 0, loop dispari (1,3,5,7). 0 corrisponde a 0.

(-3, -2, -1), (0), (1,2), (3,4,5,6)

mappe a

(-2, -1, -3), (0), (2,1), (6,3,4,5)

f=lambda x:1+2*int(abs(x)**.5)if x<1 else 2*int(x**.5+.5)
x=int(input());n=f(x)
if x>0:b=n*(n-2)/4
else:b=-((n+1)/2)**2
print(b+1+(x-b-2)%n)

Modifica: @TuukkaX ha tolto 8 byte dalla soluzione precedente. E un altro 3.


1
Io credo che si può rimuovere uno spazio prima l'istruzione if alla prima linea. E mipotrebbe essere cambiato in qualcosa di più piccolo, come ad esempio b.
Yytsi,

Ecco lo stesso programma:f=lambda x:1+2*int(abs(x)**0.5)if x<1 else 2*int(x**0.5+0.5) x=int(input()) n=f(x) if x>0:b=n*(n-2)/4 else:b=-((n+1)/2)**2 print(b+1+(x-b-2)%n)
Yytsi,

1
Grazie, @TuukkaX. Ho dimenticato la variabile a 2 caratteri 'mi'.
Magenta,

1
Ho anche cambiato input('')in input(). Le virgolette sono inutili poiché non dobbiamo stampare nulla sulla console quando vogliamo solo ottenere l'input.
Yytsi,

1
Ancora più breve. Rimossi gli zeri prima dei punti. f=lambda x:1+2*int(abs(x)**.5)if x<1 else 2*int(x**.5+.5) x=int(input());n=f(x) if x>0:b=n*(n-2)/4 else:b=-((n+1)/2)**2 print(b+1+(x-b-2)%n)
Yytsi,

2

Matlab (423)

function u=f(n),if(~n)u=n;else,x=abs(n);y=factor(x);for o=1:nnz(y),e=prod(nchoosek(y,o)',1);a=log(x)./log(e);b=find(a-fix(a)<exp(-9),1);if ~isempty(b),k=e(b);l=fix(a(b));break;end;end,if(abs(n)==1)k=2;l=0;end,if(k==2)l=l+1;x=x*2;end,e=dec2base(l,k)-48;o=xor(e,circshift(e,[0 1]));g=~o(end);if(~o|nnz(o==1)~=numel(e)-g),u=n*k;else,if((-1)^g==sign(n)),u=sign(n)*k^(base2dec([e(2:end-1) 1]+48,k)-(k==2));else,u=n*k;end,end,end
  • Non competitiva perché infrange un buon record di condoglianze per l'ultima classifica, mentre sto lottando per accorciarlo il più possibile.

  • Alcuni bug privi di senso riguardanti l'accuratezza nel matlab che non sono riuscito a trovare in alcun modo se non rendere il mio codice sarcatisticamente grande, d'altra parte la mappatura per cui ho optato era in termini di facce prime e logaritmo n-ary.

Esecuzione

 f(2)

 1

 f(1)

 2

 f(-2)

 -4

 f(-4)

 -8

 f(-8)

 -1

 f(0)

 0



 ----------------------------

Spiegazione

  • Tenendo conto, prima di tutto, che qualsiasi numero può essere scritto come prodotto di esponenti di numeri primi N=e1^x1*e2^x2...da questa base, ho scelto di mappare immagini di cicli Cche sono estratti dal più grande esponente del fattore più piccolo (non necessariamente primo) che N è un potere perfetto di .

  • in parole più semplici, lascia che N=P^xP sia la radice perfetta più piccola, xdenota esattamente due termini essenziali per il ciclo: x=Ʃ(r*P^i)un termine Pè la base del ciclo e una radice perfetta per il numero principale N, ed kè il grado del ciclo C=p^k, dove ivaria tra 1 e k, il coefficiente rviene incrementato di 1 e limitato da P-1 per qualsiasi pre-immagine successiva fino a quando tutti i coefficienti sono impostati su r = 1, quindi ci spostiamo all'inizio di quel ciclo.

  • Per evitare le collisioni tra i cicli, la scelta dell'espiazione dei numeri primi anziché dei loro prodotti è accurata, perché può essere un esempio di due cicli di basi 3e 2un punto di incontro tra loro 3*2, quindi questo è evitato poiché un ciclo è definito dal suo grado più che dal suo base e per il punto di incontro esiste un altro ciclo di base 6e grado 1.

  • I numeri negativi pongono un'eccezione, per quanto riguarda questo, ho riservato gradi dispari per i numeri negativi e gradi pari per il resto. Come mai ?

    per ogni numero N incorporato in un ciclo P^k, viene scritto come P^(a0*P^i0+a1*P^i1+...), la quantità (a0*P^i0+a1*P^i1+...)viene transaltata in base P-ary come a0,a1,...., per chiarire questo punto se (p = 2) la sequenza deve essere in base binaria. Come è noto, senza impostare la condizione di gradi positivi / negativi e l'eccezione (+/- 1), un numero N si trova sui bordi di un ciclo di gradi kse e solo se la sequenza Aè scritta come 1111..{k+1}..10o 111..{k}..1per tutte le basi, altrimenti non è necessaria alcuna rotazione, assegnando così una condizione negativa / positiva per i rispettivi gradi pari / dispari k/k'per entrambi crea una sequenza dispari scritta nella forma 101..{k}..100, una sequenza pari viene scritta nella forma 101..{k'}..10per un bordo iniziale di un ciclo numerico rispettivamente negativo / positivo .

    Esempio:

    Prendendo un numero N=2^10, x=10=2^1+2^3viene scritta la sequenza A A=1010, questo tipo di sequenza sintetizza un bordo finito del ciclo numerico positivo, che è C=2^3, quindi l'immagine successiva è quella del bordo iniziale A=011che è 8, ma , standardizzando questo risultato in (+ / -) 1 eccezione 2^10/2alle mappe 8/2e l'immagine precedente non deve essere ruotata.

    Prendendo un numero N=-3^9, x=9=3^2viene scritta la sequenza A A=100, questo tipo di sequenza sintetizza un bordo finito del ciclo numerico negativo, che è C=3^1, quindi l'immagine successiva è quella del bordo iniziale A=01che è 3, ma, adattando questo risultato a negativo / positivo la condizione viene -3^9mappata a -3.

  • per la coppia (-/+)1, ho pensato di intrometterlo in un numero di basi di cicli 2, con il pretesto che una sequenza ordinaria di gruppi ciclici fosse {2,4}{8,16,32,64}..composta in un'altra forma {1,2}{4,8,16,32}.., questo impedisce qualsiasi perdita di elementi precedenti e l'opeazione fatta si sta spostando con lo scoppio un nuovo elemento in.


risultati:

eseguendo questo piccolo foglio di codice per verificare i primi intervalli ragionevoli di numeri ciclici:

for (i=1:6) 
index=1;if(max(factor(i))>=5) index=0;end
for ind=0:index
j=f(((-1)^ind)*i); while(((-1)^ind)*i~=j)fprintf('%d ',j);j=f(j);end,fprintf('%d \n',(-1)^ind*i),pause,end,
end

Questo porta a questi risultati

 2 1 
 -2 -4 -8 -1 
 1 2 
 -4 -8 -1 -2 
 9 27 3 
 -9 -27 -81 -243 -729 -2187 -6561 -19683 -3 
 8 16 32 64 128 256 512 4 
 -8 -1 -2 -4 
 25 125 625 3125 5 
 36 216 1296 7776 46656 6 
 -36 -216 -1296 -7776 -46656 -279936 -1679616 -10077696 -60466176 -362797056 -2.176782e+009 -1.306069e+010 ??? Error using ==> factor at 27

L'ultimo è un errore di segmentazione ma si adatta all'intervallo standard con segno intero [-127,127].


Ho usato questa tecnica qualche tempo fa per definire le funzioni di hash in un mio vecchio programma C, funziona perfettamente!
Abr001am

0

JavaScript (ES6), 73 byte

f=(n,i=0,j=0,k=0,l=1,m=i<0?-i:~i)=>n-i?f(n,m,k++?j:i,k%=l,l+!k):++k-l?m:j

Lavora enumerando la sequenza (0, -1, 1, -2, 2, -3, 3, ...) fino a quando non trova n, contando i cicli mentre procede. icontiene la voce corrente; jcontiene l'inizio del ciclo corrente, kl'indice all'interno del ciclo, lla lunghezza del ciclo corrente e mla voce successiva nella sequenza. Una volta trovato, nprendiamo quindi jse siamo alla fine di un ciclo o in mcaso contrario.

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.