Genera una coppia di numeri interi da uno non negativo


25

È necessario scrivere un programma o una funzione che accetta un numero intero non negativo Ncome input e restituisce o restituisce due numeri interi (negativo, zero o positivo) Xe Y.

I numeri interi sono intesi in senso matematico in quanto ce ne sono infiniti.

La funzione implementata deve essere biiettiva . Ciò significa che per ogni Nuscita deve essere emessa una X Ycoppia diversa e ogni X Ycoppia deve essere emessa per alcuni input, Novvero tutte le seguenti coppie dovrebbero essere emesse per alcuni N:

                 ...
    ┌─────┬─────┬────┬────┬────┐
    │-2 -2│-2 -1│-2 0│-2 1│-2 2│
    ├─────┼─────┼────┼────┼────┤
    │-1 -2│-1 -1│-1 0│-1 1│-1 2│
    ├─────┼─────┼────┼────┼────┤
... │0 -2 │0 -1 │0 0 │0 1 │0 2 │ ...
    ├─────┼─────┼────┼────┼────┤
    │1 -2 │1 -1 │1 0 │1 1 │1 2 │
    ├─────┼─────┼────┼────┼────┤
    │2 -2 │2 -1 │2 0 │2 1 │2 2 │
    └─────┴─────┴────┴────┴────┘
                 ...

Si noti che U Ve V Usono coppie diverse se U!=V.

Dettagli

  • Se la tua lingua non supporta numeri interi arbitrariamente grandi, va bene, ma l'algoritmo dovrebbe funzionare con un tipo di dati intero arbitrariamente grande. Il tuo codice dovrebbe comunque supportare i valori di input per almeno 2^31-1.
  • Se si sceglie di stampare o restituire l'output come stringa, non sono consentiti segni 0o +segni iniziali. Altrimenti la rappresentazione intera standard della tua lingua va bene.

Esempio

Se il compito fosse quello di fare una funzione biiettiva prendendo un numero intero non negativo Ne produrre un numero intero, la Xsoluzione potrebbe essere la funzione

if (input mod 2 == 0) return N/2 else return -(N+1)/2,

implementato in alcune lingue. Questa funzione ritorna X = 0 -1 1 -2 2...per N = 0 1 2 3 4....


Qualunque numero intero nell'output può essere ripetuto per input diversi? ad es. 10=>11 12, 9=>10 11questo non è valido perché 11 viene ripetuto?
BrainSteel

1
Per quanto riguarda "biiettivo" è definito "11 12" non uguale a "10 11" e quindi valido. Questo perché una funzione biiettiva è definita come una funzione "in cui ogni elemento di un set è associato esattamente a un elemento dell'altro set e ogni elemento dell'altro set è associato esattamente a un elemento del primo set. Non ci sono elementi spaiati "( en.wikipedia.org/wiki/Bijection ). Se dovessi invertire la tua funzione "11 12" dovrebbe emettere 10 e "10 11" dovrebbe emettere 9.
GiantTree

@BrainSteel Il tuo esempio è valido. Solo le coppie (ordinate) non possono essere ripetute. GiantTree è corretto. Aggiunte altre spiegazioni alla domanda.
randomra,

Deve essere una biiezione all'interno dell'intervallo intero della lingua data o dovrebbe funzionare per tutti gli interi?
Flawr,

1
@LegionMammal aveva una buona descrizione matematica dell'attività: "Devi definire una funzione biiettiva $ f: N + → Z ^ 2 $. - LegionMammal978." che penso sarebbe utile da qualche parte nella dichiarazione
Brian J

Risposte:


15

Pyth, 15

u,-HyeGhGjQ2,ZZ

Provalo online.

u             reduce
                lambda G,H:    [implicit]
  ,-HyeGhG         (H-2*G[-1],G[0])
  jQ2           base(input(),2)
  ,ZZ           (0,0)
              print result     [implicit]

Una traduzione Python:

g=lambda Z,n:(n-2*Z[1],Z[0])
print reduce(g,binlist(input()),(0,0))

o iterativamente:

(x,y)=(0,0)
for b in binlist(input()):
    (x,y)=(b-2*y,x)
print (x,y)

dove binlistconverte un numero in un elenco di cifre come binlist(4) = [1,0,0].

Quindi, come funziona? Interpreta le cifre binarie del numero come due numeri interlacciati in due negativi di base come nella mia soluzione Python .n

Il numero binario corrisponde alla coppia ( x , y ) = ( b 0 - 2 b 2 + 4 b 4 - 8 b 6 + , b 1 - 2 b 3 + 4 b 5 - 8 b 7 + )

n=...B5B4B3B2B1B0
(X,y)=(B0-2B2+4B4-8B6+,B1-2B3+4B5-8B7+).

Se non avessimo ancora elaborato l'ultima cifra di n , avremmo tutti gli indici più alti di $ 1 $, n = b 5 b 4 b 3 b 2 b 1 corrispondente alla coppia ( x , y ) = ( b 1 - 2 b 3 + 4 b 5 - 8 b 7 + , b 2 - 2 b 4B0n

n'=...B5B4B3B2B1
(X',y')=(B1-2B3+4B5-8B7+,B2-2B4+4B6-8B8+).

Possiamo quindi esprimere i nuovi valori una volta che viene letto in termini di vecchi valoriB0

(X,y)=(B0-2y',X').

(X,y)(B-2y,X)Bn(X,y)


Si noti che il supporto MathJax è stato disabilitato. Potresti prendere in considerazione la possibilità di modificare la tua spiegazione per leggibilità.
Alex A.

32

CJam, 24 22 21 byte

Il mio cervello ha difficoltà a capire la matematica che stanno usando altre soluzioni. Ma il mio cervello capisce sicuramente il binario, quindi ecco un'anima basata sulla manipolazione dei bit!

li4b2fmd2/z{)(\2b^}%p

Provalo online.

Spiegazione

Questo approccio considera l'input come due valori binari interlacciati, uno per ciascun numero di output. Tutti tranne il bit meno significativo di ciascuno codificano una grandezza, e il bit meno significativo segnala se prendere o meno il complemento bit a bit di questa grandezza. In questa implementazione, i bit posizionati in modo dispari corrispondono al primo numero in uscita (e i bit in posizione pari corrispondono al secondo) e un LSB di 0segnali per prendere il complemento.

Ad esempio, dato un input di 73, non lievitando la sua rappresentazione binaria di 1001001bproduce 0 1|0(bit dispari posizionati) e 1 0 0|1(bit posizionati pari). Il primo valore ha una grandezza di 01b = 1e dovrebbe essere integrato per un valore finale di ~1 = -2, e il secondo valore ha una grandezza di 100b = 4e non dovrebbe essere integrato.

Dimostrazione informale di correttezza

Ho creato un programma di test che posiziona ogni input da zero a un numero specificato dall'utente meno uno nella sua posizione di output su una griglia 2D. Puoi provarlo anche online . Ecco un output di questo programma che mostra come viene mappato l'algoritmo 0-99:

      -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8

-8                      92 84 86 94                     
-7                      88 80 82 90                     
-6                      76 68 70 78                     
-5                   96 72 64 66 74 98                  
-4                60 52 28 20 22 30 54 62               
-3                56 48 24 16 18 26 50 58               
-2                44 36 12  4  6 14 38 46               
-1                40 32  8  0  2 10 34 42               
 0                41 33  9  1  3 11 35 43               
 1                45 37 13  5  7 15 39 47               
 2                57 49 25 17 19 27 51 59               
 3                61 53 29 21 23 31 55 63               
 4                   97 73 65 67 75 99                  
 5                      77 69 71 79                     
 6                      89 81 83 91                     
 7                      93 85 87 95                     
 8                                                      

Il pattern di riempimento sembra un po 'strano, ma in realtà è biiettivo! Ad ogni successiva potenza di 4, riempie un quadrato con il doppio della lunghezza laterale precedente. Ad esempio, ecco come viene mappato l'algoritmo 0-15:

      -2 -1  0  1  2

-2    12  4  6 14   
-1     8  0  2 10   
 0     9  1  3 11   
 1    13  5  7 15   
 2                  

Questo costituisce il quadrato 4x4 al centro del quadrato 8x8 di 0-63:

      -4 -3 -2 -1  0  1  2  3  4

-4    60 52 28 20 22 30 54 62   
-3    56 48 24 16 18 26 50 58   
-2    44 36 12  4  6 14 38 46   
-1    40 32  8  0  2 10 34 42   
 0    41 33  9  1  3 11 35 43   
 1    45 37 13  5  7 15 39 47   
 2    57 49 25 17 19 27 51 59   
 3    61 53 29 21 23 31 55 63   
 4                              

Che costituisce il quadrato 8x8 al centro del quadrato 16x16 di 0-255:

         -8  -7  -6  -5  -4  -3  -2  -1   0   1   2   3   4   5   6   7   8

 -8     252 244 220 212 124 116  92  84  86  94 118 126 214 222 246 254    
 -7     248 240 216 208 120 112  88  80  82  90 114 122 210 218 242 250    
 -6     236 228 204 196 108 100  76  68  70  78 102 110 198 206 230 238    
 -5     232 224 200 192 104  96  72  64  66  74  98 106 194 202 226 234    
 -4     188 180 156 148  60  52  28  20  22  30  54  62 150 158 182 190    
 -3     184 176 152 144  56  48  24  16  18  26  50  58 146 154 178 186    
 -2     172 164 140 132  44  36  12   4   6  14  38  46 134 142 166 174    
 -1     168 160 136 128  40  32   8   0   2  10  34  42 130 138 162 170    
  0     169 161 137 129  41  33   9   1   3  11  35  43 131 139 163 171    
  1     173 165 141 133  45  37  13   5   7  15  39  47 135 143 167 175    
  2     185 177 153 145  57  49  25  17  19  27  51  59 147 155 179 187    
  3     189 181 157 149  61  53  29  21  23  31  55  63 151 159 183 191    
  4     233 225 201 193 105  97  73  65  67  75  99 107 195 203 227 235    
  5     237 229 205 197 109 101  77  69  71  79 103 111 199 207 231 239    
  6     249 241 217 209 121 113  89  81  83  91 115 123 211 219 243 251    
  7     253 245 221 213 125 117  93  85  87  95 119 127 215 223 247 255    
  8                                                                        

3
Molto intelligente! È possibile salvare due byte utilizzando li4b2fmd2/invece di 0li2b+W%2/W%. Questo dà gli stessi numeri interi, ma in ordine inverso.
Dennis,

@Dennis Anche questo è molto intelligente. Ho aggiornato la risposta per usare quel trucco. Grazie!
Runer112,

12

Python 2, 49

Modifica: migliorato a 49 utilizzando una migliore ricorsione in un passaggio per base -2.

def f(n):x,y=n and f(n/2)or(0,0);return n%2-2*y,x

Ecco una versione di Pyth che utilizza reduce.

Modifica: migliorato a 52 passando alla base -2 dal ternario bilanciato .

Python 2, 52

h=lambda n:n and n%2-2*h(n/4)
lambda n:(h(n),h(n/2))

Python 2, 54

h=lambda n:n and-~n%3-1+3*h(n/9)
lambda n:(h(n),h(n/3))

Questo utilizza l'interlacciamento delle cifre come la soluzione di Runer112 , ma con ternario bilanciato anziché binario con segno . Python non ha una conversione di base integrata, quindi il codice lo implementa in modo ricorsivo.

La funzione helper h(con 3al posto del 9) prende un numero naturale e lo converte da ternario a ternario bilanciato con le sostituzioni delle cifre

0 -> 0 
1 -> +1
2 -> -1

Quindi, ad esempio, 19, che è 201 in base, diventa (-1) (0) (+ 1) in ternario bilanciato, che è (-1) * 3 ^ 2 + (0) * 3 ^ 1 + (+ 1) * 3 ^ 0 = -8.

Il ternario bilanciato è sufficiente per codificare ogni numero intero e quindi fornisce una mappatura da numeri naturali a numeri interi.

Per mappare su coppie di numeri interi, intercaliamo le cifre n. Per fare ciò, abbiamo hesaminato ogni altra cifra facendo n/9come il passo ricorsivo piuttosto che n/3. Quindi, per una coordinata, ci spostiamo ndividendo il pavimento per 3.

Ecco le prime 81 uscite, che coprono la regione [-4,4] ^ 2.

0 (0, 0)
1 (1, 0)
2 (-1, 0)
3 (0, 1)
4 (1, 1)
5 (-1, 1)
6 (0, -1)
7 (1, -1)
8 (-1, -1)
9 (3, 0)
10 (4, 0)
11 (2, 0)
12 (3, 1)
13 (4, 1)
14 (2, 1)
15 (3, -1)
16 (4, -1)
17 (2, -1)
18 (-3, 0)
19 (-2, 0)
20 (-4, 0)
21 (-3, 1)
22 (-2, 1)
23 (-4, 1)
24 (-3, -1)
25 (-2, -1)
26 (-4, -1)
27 (0, 3)
28 (1, 3)
29 (-1, 3)
30 (0, 4)
31 (1, 4)
32 (-1, 4)
33 (0, 2)
34 (1, 2)
35 (-1, 2)
36 (3, 3)
37 (4, 3)
38 (2, 3)
39 (3, 4)
40 (4, 4)
41 (2, 4)
42 (3, 2)
43 (4, 2)
44 (2, 2)
45 (-3, 3)
46 (-2, 3)
47 (-4, 3)
48 (-3, 4)
49 (-2, 4)
50 (-4, 4)
51 (-3, 2)
52 (-2, 2)
53 (-4, 2)
54 (0, -3)
55 (1, -3)
56 (-1, -3)
57 (0, -2)
58 (1, -2)
59 (-1, -2)
60 (0, -4)
61 (1, -4)
62 (-1, -4)
63 (3, -3)
64 (4, -3)
65 (2, -3)
66 (3, -2)
67 (4, -2)
68 (2, -2)
69 (3, -4)
70 (4, -4)
71 (2, -4)
72 (-3, -3)
73 (-2, -3)
74 (-4, -3)
75 (-3, -2)
76 (-2, -2)
77 (-4, -2)
78 (-3, -4)
79 (-2, -4)
80 (-4, -4)

Una codifica alternativa con un quarto di immaginario è risultata più lunga, sebbene sia molto carina.

Python 2, 63

h=lambda n:n and n%4+2j*h(n/4)
lambda n:(h(n).real,h(n).imag/2)

In una lingua con una gestione meno complessa della conversione complessa, questo sarebbe probabilmente un approccio migliore. Se potessimo produrre numeri complessi, potremmo fare:

Python 2, 38

f=lambda n:n and n%2+n/2%2*1j-2*f(n/4)

1
La tua funzione di base -2 originale sarebbe una risposta Pyth media. L&b-%b2*2y/b4,yQy/Q2è lungo solo 20 byte.
Dennis,

4
@Dennis Ho appena scritto una soluzione Pyth da 15 caratteri.
xnor

Ternario bilanciato e quarto immaginario. Due delle mie basi preferite. Seguito solo da Base-e.
Brian Minton,

11

Python 2, 98 byte

Cominciamo con un approccio semplice:

def f(N):
 x=a=0;b=2
 while N:x+=1j**b;b+=a<1;a=a or b/2;N-=1;a-=1
 return int(x.real),int(x.imag)

Forma solo una spirale rettangolare Nlunga su una griglia 2d, a partire dall'origine, e restituisce le coordinate dell'ultimo punto.

La funzione è biiettiva poiché:

  • Ogni punto può essere coperto, data una spirale abbastanza lunga
  • Ogni punto sarà intersecato dalla spirale una sola volta

La spirale è simile a questa (tranne che per iniziare da 0 anziché 1):

Spirale di Ulam


@AlexA. 0**0 == 1in pitone, quindi è lo stesso diif a == 0: a = b/2
grc

Bene, grazie per aver spiegato.
Alex A.

@AlexA. risulta a=a or b/2più breve
grc

@grc 0^0=1in tutta la matematica, non solo in pitone.
Daenyth,

1
@Daenyth 0**0è in realtà una forma indeterminata in matematica
Sp3000,

8

dc, 49

[1+2~2*1-*n]sm?dsa8*1+v1-2/dd1+*2/lar-dlmx32P-lmx

Questo inizia organizzando gli interi non negativi su una griglia in questo modo:

..| 
4 | 14
3 |  9 13
2 |  5  8 12
1 |  2  4  7 11
0 |  0  1  3  6 10
Y +-----------------
  X  0  1  2  3  4 ...

Si noti che il modo in cui le posizioni della griglia vengono riempite in diagonale all'aumentare di N. Notare che la linea Y = 0 contiene la sequenza numerica triangolare, data da N = X(X+1)/2. Questa è un'equazione quadratica che viene risolta usando la formula normale, usando solo la radice + ve, in modo che possiamo determinare X da N quando Y = 0. Segue un semplice mescolamento aritmetico per dare {X, Y} unico per ogni N.

Ciò fornisce la qualità biiettiva richiesta, ma X e Y sono solo non negativi, ma la domanda richiede tutti i possibili numeri interi. Quindi X e Y sono mappati usando ((t+1)/2)*((t+1)~2*2-1)per dare tutti i possibili numeri interi.

dcha numeri di precisione arbitrari, quindi l'intervallo di input per 2^31-1non è un problema. Si noti inoltre che la precisione di default è 0 cifre decimali, e la sqrt()e /rotonda verso il basso che è il comportamento necessario qui.

Produzione:

$ for i in {0..10}; do dc biject.dc <<< $i; echo; done
0 0
0 -1
-1 0
0 1
-1 -1
1 0
0 -2
-1 1
1 -1
-2 0
0 2
$

5

Matlab, 54 byte

n=input('')+1;[i,j]=find(spiral(2*n)==n);disp([i,j]-n)

La chiave qui è spiral, questo crea una matrice a spirale di dimensioni arbitrarie.

spiral(3)

ritorna

ans =

 7     8     9
 6     1     2
 5     4     3

spiral4n2n104n1052.91011n=232


2

Haskell, 78 74 byte

(concat[[(x,i-x),(x,x-1-i),(-1-x,x-1-i),(-1-x,i-x)]|i<-[0..],x<-[0..i]]!!)

Prova:

*Main> mapM_ (print . (concat[[(x,i-x),(x,x-1-i),(-1-x,x-1-i),(-1-x,i-x)]|i<-[0..],x<-[0..i]]!!) ) [0..20]
(0,0)
(0,-1)
(-1,-1)
(-1,0)
(0,1)
(0,-2)
(-1,-2)
(-1,1)
(1,0)
(1,-1)
(-2,-1)
(-2,0)
(0,2)
(0,-3)
(-1,-3)
(-1,2)
(1,1)
(1,-2)
(-2,-2)
(-2,1)
(2,0)

Come funziona: elenca tutte le coppie nel primo quadrante nel seguente ordine

  |
 2| #4
  |
 1| #2  #5
  | 
 0| #1  #3  #6
  +---------------
     0   1   2   3 

rispecchia ciascun punto negli altri quadranti per creare un elenco di 4 elenchi di elementi. Concatena tutto in un unico elenco e prendi l' nelemento th.

Modifica: la funzione non ha bisogno di un nome, matematica riordinata. espressioni.


Puoi salvare 4 byte usando do-notation: provalo online!
ბიმო

1

Haskell , 50 byte

(0!).succ
l!n=(last$(!).succ:[(,)|odd n])l$div n 2

Provalo online o provalo con il suo contrario!

Ungolfed

ntoN2 n = 0 ! (n + 1)

xCounter ! remainingNum
  | odd remainingNum = (xCounter, div remainingNum 2)
  | otherwise        = (xCounter + 1) ! div remainingNum 2

Spiegazione

(X,y)N22X(2y+1)-1N(!)XlxCountery

Si noti che la funzione effettiva f( ntoN2) incrementa l'ingresso prima di iniziare con la procedura.


1

05AB1E , 35 byte

>©DÝʒo®sÖ}àsÅÉʒ®sÖ}à<2÷‚εDÈi2÷ë>2÷(

Provalo online! o come suite di test

Spiegazione

Ritenere

f:NN×Nn(X,y),
X2Xn+12y+1n+1ff-1(X,y)=2X(2y+1)-1

g:N×NZ×Z(m,n)(h(m),h(n)),
h:NZn{n2,n anche-n+12,n dispari.
fghgf:NZ×Z

gf

>©DÝʒo®sÖ}àsÅÉʒ®sÖ}à<2÷‚εDÈi2÷ë>2÷( # Full program

                                    # Implicit input: Integer n
>©                                  # Compute n+1 and save it to the register
  DÝ                                # Duplicate n+1 and push the list [0,...,n+1]
    ʒo®sÖ}                          # Only keep those numbers x so that 2^x divides n+1
          à                         # Get maximum element in the list.
           sÅÉ                      # Swap so that n+1 is on top and push [1,3,5,...,n+1]
              ʒ®sÖ}                 # Only keep those numbers z which divides n+1
                   à<2÷             # Compute y = (z-1)/2
                       ‚            # Push the pair [x,y]
                        ε           # Apply the function h to x (and y):
                           i        # if...
                         DÈ         # x is even
                            2÷      # then compute x/2
                              ë>2÷( # else compute -(x+1)/2
                                    # Implicit output: [h(x),h(y)]

wow, votato per la bella spiegazione. ma sicuramente 05AB1E dovrebbe essere in grado di battere Pyth?
ASCII il

gf

0

Mathematica, 46

SortBy[Tuples[Range[2#]-#,2],Norm][[#]]&[#+1]&

Ordina i vettori secondo la loro norma, quindi prendi il nth.


0

JavaScript, 166 168 byte / caratteri

Nuovo approccio usando una spirale rettangolare come stanno usando gli altri.

function f(n){return b=Math,k=b.ceil((b.sqrt(n)-1)/2),t=2*k+1,m=b.pow(t,2),t+=4,m-t>n?(m-=t,m-t>n?(m-=t,m-t>n?[k,k-(m-n-t)]:[-k+(m-n),k]):[-k,-k+(m-n)]):[k-(m-n),-k]}

Ho usato questa risposta su Math.SE, tradotta in JS e compressa con UglifyJS .

Questo approccio non utilizza alcun loop né crea la spirale in alcun modo.

f:N0Z2

Aggiornamento: salvato 2 caratteri memorizzandoli Mathin b.

t-=1t+=4f(0)=f(8)N00


1) Ripubblicare la stessa identica domanda non sarà di grande aiuto. 2) Copiare un'altra risposta e quindi usare un minificatore per giocare a golf non lo farà :)
Ottimizzatore

Almeno segue tutte le regole indicate nella domanda ed è un approccio diverso. Inoltre non sto rubando il lavoro di un altro, ma mi riferisco ad esso su come ho fatto questa risposta.
GiantTree,

@Optimizer: 1) Ho suggerito a GiantTree di ripubblicare da quando ha ottenuto 3 (meritevoli) voti negativi per il suo approccio originale e non valido. 2) Il codice che ha preso da Math.SE non è nemmeno JavaScript, quindi ha fatto molto di più che copiarlo in un minificatore.
Dennis,

@Dennis le persone possono ritirare il loro voto negativo, lo sai. Inoltre, l'uso di un minificatore per minimizzare il codice non è davvero incoraggiato imo.
Ottimizzatore

@Optimizer Ho provato a golfare il codice, ma l'uso di un compressore ha portato a un risultato migliore (meno caratteri), quindi ho usato quello.
GiantTree,
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.