Утворіть пару цілих чисел із негативних


25

Ви повинні написати програму або функцію, яка приймає невід'ємне ціле число Nяк вхід і вихід або повертає два цілих числа (від'ємне, нульове або додатне) Xі Y.

Цілі цілі мають на увазі математичний сенс, оскільки їх нескінченно багато.

Реалізована функція повинна бути біективною . Це означає, що для кожної з Nних повинна виводитися інша X Yпара, і кожна X Yпара повинна виводитися на деякий вхід, Nтобто всі наступні пари повинні бути виведені для деяких 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 │
    └─────┴─────┴────┴────┴────┘
                 ...

Зауважте, що U Vі V Uє різні пари, якщо U!=V.

Деталі

  • Якщо ваша мова не підтримує довільно великих цілих чисел, це добре, але ваш алгоритм повинен працювати з довільно великим цілим типом даних. Ваш код все одно повинен підтримувати вхідні значення принаймні 2^31-1.
  • Якщо ви вирішили надрукувати або повернути вихід у вигляді рядка, то жодні провідні знаки 0та +знаки заборонені. Інакше стандартне ціле представлення вашої мови добре.

Приклад

Якщо завдання полягатиме в тому, щоб зробити біективну функцію, приймаючи невід'ємне ціле число Nі вивести одне ціле число, Xрішенням може бути функція

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

реалізовані якоюсь мовою. Ця функція повертається X = 0 -1 1 -2 2...для N = 0 1 2 3 4....


Чи можна повторити будь-яке з цілих чисел на різному введенні? наприклад 10=>11 12, 9=>10 11, це недійсно, оскільки 11 повторюється?
BrainSteel

1
Наскільки "бієктив" визначено "11 12", не те саме, що "10 11" і тому діє. Це пояснюється тим, що бієктивна функція визначається як функція ", коли кожен елемент одного набору поєднується з точно одним елементом іншого набору, а кожен елемент іншого набору поєднується з точно одним елементом першого набору. Немає непарні елементи. "( en.wikipedia.org/wiki/Bijection ). Якщо ви повинні перевернути свою функцію, "11 12" має вивести 10, а "10 11"
GiantTree

@BrainSteel Ваш приклад дійсний. Тільки (упорядковані) пари не можуть бути повторені. GiantTree правильно. Додано ще кілька пояснень до питання.
randomra

Чи має бути біекція в цілому діапазоні даної мови, або вона повинна працювати для всіх цілих чисел?
flawr

1
@LegionMammal мав хороший математичний опис завдання: "Вам потрібно визначити бієктивну функцію $ f: N + → Z ^ 2 $. - LegionMammal978." що я думаю, було б корисно десь у висловлюванні
Брайан Дж

Відповіді:


15

Піт, 15

u,-HyeGhGjQ2,ZZ

Спробуйте в Інтернеті.

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

Переклад Python:

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

або повторно:

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

де binlistперетворює число в список подібних цифр binlist(4) = [1,0,0].

Отже, як це працює? Він інтерпретує двійкові цифри числа n як два переплетених числа в базових від’ємних двох, як у моєму рішенні Python .

Двійкове число відповідає парі ( 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)=(b02b2+4b48b6+,b12b3+4b58b7+).

Якби ми ще не обробили останню цифру з n , у нас були б усі індекси вищі на $ 1 $, n ' = ... b 5 b 4 b 3 b 2 b 1, що відповідають пари ( x , y ) = ( b 1 - 2 b 3 + 4 b 5 - 8 b 7 + , b 2 - 2 b 4b0n

n=b5b4b3b2b1
(x,y)=(b12b3+4b58b7+,b22b4+4b68b8+).

b0

(x,y)=(b02y,x).

(x,y)(b2y,x)bn(x,y) яка походить від вилучення її цифр.


Зауважте, що підтримка MathJax відключена. Ви можете розглянути можливість редагування пояснення щодо читабельності.
Олексій А.

32

CJam, 24 22 21 байт

Мій мозок має проблеми з розумінням математики, яку використовують інші рішення. Але мій мозок напевно розуміє бінарне, тож ось думка, заснована на бітовій маніпуляції!

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

Спробуйте в Інтернеті.

Пояснення

Цей підхід розглядає вхід як два переплетених двійкових значення, по одному для кожного вихідного числа. Всі, окрім найменш значущого біта кожного кодують величину, і найменш значущий біт сигналізує про те, приймати чи ні бітовий доповнення цієї величини. У цій реалізації непарні позиції бітів відповідають першому вихідному номеру (а парні біти відповідають другому) та LSB 0сигналів для прийому комплементу.

Наприклад, якщо введення 73, uninterleaving його двійкове подання 1001001bвиробляє 0 1|0(непарні біти розташовані) і 1 0 0|1(навіть позиціонування біт). Перше значення має величину 01b = 1і має бути доповнене для кінцевого значення ~1 = -2, а друге значення має величину 100b = 4і не повинно доповнюватися.

Неформальна демонстрація правильності

Я зробив програму тестування, яка розміщує кожен вхід від нуля до вказаного користувачем числа мінус один у його вихідному місці на 2D сітці. Ви можете спробувати і в Інтернеті . Ось результат цієї програми, який показує, як алгоритм відображає 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                                                      

Шаблон заливки виглядає дещо дивно, але насправді це бієктично! З кожною наступною потужністю 4, вона заповнює квадрат, подвійний попередній бічній довжині. Наприклад, ось як алгоритм відображає 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                  

Це становить 4х4 квадрат посередині 8х8 квадрата 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                              

Який складає 8х8 квадрат посередині 16х16 квадрата 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
Дуже розумний! Ви можете зберегти два байти, використовуючи li4b2fmd2/замість 0li2b+W%2/W%. Це дає ті самі цілі числа, але в зворотному порядку.
Денніс

@Dennis Це теж дуже розумно. Я оновив відповідь, щоб використовувати цей трюк. Спасибі!
Runer112

12

Пітон 2, 49

Редагування: Покращено до 49 за допомогою кращої одноетапної рекурсії для бази -2.

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

Ось версія з використанням Pythreduce .

Редагування: Покращено до 52 шляхом переходу на базу -2 із збалансованого потрійного .

Пітон 2, 52

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

Пітон 2, 54

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

Для цього використовується перемежування цифр, як рішення Runer112 , але з збалансованим потрійним, а не підписаним двійковим. У Python немає вбудованої базової конверсії, тому код реалізує це рекурсивно.

Функція помічника h3замість цього 9) приймає натуральне число і перетворює її з потрійного у врівноважене потрійне з цифровими підмінами

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

Так, наприклад, 19, що становить 201 в основі, стає (-1) (0) (+ 1) в збалансованому потрійному, що є (-1) * 3 ^ 2 + (0) * 3 ^ 1 + (+ 1) * 3 ^ 0 = -8.

Збалансованого потрійного достатньо для кодування кожного цілого числа, і таким чином дає відображення від натуральних чисел до цілих чисел.

Щоб відобразити пари на цілі числа, переплутаємо цифри n. Для цього ми hрозглядаємо кожну іншу цифру, роблячи n/9скоріше рекурсивний крок, а неn/3 . Потім по одній координаті зміщуємо nна поділ підлоги на 3.

Ось перші 81 виходи, які охоплюють область [-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)

Альтернативне кодування з чверть уявним виявилося довше, хоча воно дуже гарне.

Пітон 2, 63

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

Мовою з менш химерною обробкою складного перетворення, це, мабуть, буде кращим підходом. Якби ми могли вивести складні числа, ми могли б зробити:

Пітон 2, 38

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

1
Ваша оригінальна функція базовий -2 склала б середню відповідь Pyth. L&b-%b2*2y/b4,yQy/Q2всього 20 байт.
Денніс

4
@Dennis Я щойно написав 15-ти чарове рішення Pyth.
xnor

Збалансований потрійний і чверть-уявний. Дві мої улюблені бази. Слідкує лише Base-e.
Брайан Мінтон

11

Python 2, 98 байт

Почнемо з простого підходу:

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)

Він просто утворює прямокутну спіраль N одиниці довгою на 2d сітці, починаючи від початку, і повертає координати останньої точки.

Ця функція бієктивна, оскільки:

  • Кожну точку можна прикрити, задавши досить довгу спіраль
  • Кожна точка буде перетинатися спіраллю лише один раз

Спіраль виглядає приблизно так (за винятком того, що починається з 0, а не 1):

Ulam Spiral


@AlexA. 0**0 == 1в python, тож це точно так само, якif a == 0: a = b/2
grc

Класно, дякую за пояснення.
Олексій А.

@AlexA. виявляється a=a or b/2коротше
гр.кр

@grc 0^0=1з усієї математики, а не лише python.
Daenyth

1
@Daenyth 0**0насправді невизначена форма з математики
Sp3000

8

постійний струм, 49

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

Це починається з упорядкування нерегулярних цілих чисел у сітці таким чином:

..| 
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 ...

Зауважте, що, як позиції сітки заповнюються по діагоналі зі збільшенням N. Зауважте, рядок Y = 0 містить трикутну послідовність чисел, задану виразом N = X(X+1)/2 . Це квадратичне рівняння, яке розв’язується за звичайною формулою, використовуючи лише корінь + ve, щоб ми могли визначити X з N, коли Y = 0. Далі - кілька простих арифметичних перетасовок, щоб дати унікальні {X, Y} для кожного N.

Це забезпечує необхідну біективну якість, але X і Y є лише негативними, але питання вимагає всіх можливих цілих чисел. Тож X і Y відображаються за допомогою ((t+1)/2)*((t+1)~2*2-1)давання всіх можливих цілих чисел.

dcмає довільні цифри точності, тому діапазон введення для сигналу не 2^31-1є проблемою. Слід також зазначити , що точність по умовчанням 0 десяткових цифр, а sqrt()й /цілий вниз , що це поведінка потрібно тут.

Вихід:

$ 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

Матлаб, 54 байти

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

Ключовим тут є те spiral, що це створює спіральну матрицю довільного розміру.

spiral(3)

повертає

ans =

 7     8     9
 6     1     2
 5     4     3

У Matlab це працює для цілих чисел, але ви отримаєте проблеми з пам’яттю до цього, (ну, я вважаю вас командою spiral створює спочатку повну матрицю, яка має розмір приблизно4н2. Навколон104ця матриця займає більше 1 Гб місця. Тож з 1 ТБ оперативної пам’яті ви зможете обійтисьн105, і о 2.91011 Гбайт оперативної пам’яті допоможе вам н=232.


2

Haskell, 78 74 байт

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

Пробіг:

*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)

Як це працює: перерахуйте всі пари в першому квадранті в наступному порядку

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

відобразити кожну точку в інші квадрати, щоб скласти список із 4-х списків елементів. Об’єднайте всі в один список і візьміть nth елемент.

Редагувати: функція не потребує імені, перепорядкованої математики. вирази.


Ви можете зберегти 4 байти за допомогою do-notation: Спробуйте це в Інтернеті!
ბიმო

1

Haskell , 50 байт

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

Спробуйте в Інтернеті або спробуйте з його зворотним!

Безумовно

ntoN2 n = 0 ! (n + 1)

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

Пояснення

Для цього використовується той факт, що кожен (х,у)N2 може бути відображено з 1 по 1 2х(2у+1)-1N. Вищеописаний оператор (!)обчислюєхрозділивши вхід до тих пір, поки він є рівним, відстежуючи нульову ініціалізовану змінну l( xCounter). Як тільки ми дійшли до парного числа, обчислюється ціле ділення y.

Зауважте, що фактична функція f( ntoN2) збільшує вхід перед початком процедури.


1

05AB1E , 35 байт

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

Спробуйте в Інтернеті! або як Тестовий набір

Пояснення

Розглянемо

f:NN×Nн(х,у),
де х є найбільшою кількістю, так що 2х розділяє н+1, і де 2у+1 - найбільше непарне число, яке ділиться н+1. Зворотнеf є відомим біекція f-1(х,у)=2х(2у+1)-1.

Тоді розглянемо

г:N×NZ×Z(м,н)(год(м),год(н)),
де
год:NZн{н2,н навіть-н+12,н дивно.
З тих пір f, г і год все це біекція, композиція гf:NZ×Z є біекція.

Програма просто обчислює гf.

>©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)]

ого, прихильне за приємне пояснення. але напевно 05AB1E повинен бути в змозі перемогти Pyth?
Лише ASCII

Дякую :) Напевно можна вдосконалити, але, ймовірно, доведеться використовувати інший підхід, а не обчислювальну техніку гf. Можливо, можливо, гольф трохи нижче, але, мабуть, не дуже підозрюю
Віслав

0

Математика, 46

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

Сортуйте вектори за їхньою нормою, а потім приймайте nго.


0

JavaScript, 166 168 байт / символів

Новий підхід із використанням прямокутної спіралі, як і інші.

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]}

Я використав цю відповідь на Math.SE, переклав її на JS і стиснув її за допомогою UglifyJS .

Цей підхід не використовує жодних циклів, а також не створює спіраль жодним чином.

Оскільки координати спіралі охоплюють усі цілі числа, функція є бієктивною в сенсі f:N0Z2.

Оновлення: Збережено 2 символи на зберігання Mathв b.

Update 2: Замінено t-=1з t+=4вирішити проблему, що викликалаf(0)=f(8). Це більше не генерує спіраль, але працює для всіх негативних чиселN0 (усі натуральні числа, включаючи 0).


1) Reposting the exact same question won't really help. 2) Copying another answer and then using a minifier for golfing won't too :)
Optimizer

At least it follows all the rules stated in the question and it's a different approach. Also I am not stealing another one's work, but I refer to it on how I made this answer.
GiantTree

@Optimizer: 1) I suggested GiantTree should repost since he got 3 (deserving) downvotes for his original, invalid approach. 2) The code he took from Math.SE isn't even JavaScript, so he did more than just copying it in a minifier.
Dennis

@Dennis people can retract their downvote, you know. Also, using a minifier to minify code is not really encouraged imo.
Optimizer

@Optimizer I tried to golf the code, but using a compressor led to a better result (less characters) so I used that one instead.
GiantTree
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.