Підведення підсумків представництва Зекендорфа


14

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


Нехай F n - n -те число Фібоначчі, де

F 1 = 1,
F 2 = 2 і
для всіх k > 2, F k = F k - 1 + F k - 2 .

Представлення Зекендорфа Z ( n ) невід'ємного цілого числа n - це набір позитивних цілих чисел, таких, що

n = Σ i ∈ Z ( n ) F i   і
i ∈ Z ( n ) i + 1 ∉ Z ( n ).

(у прозі: подання Зекендорфа числа n - це набір позитивних цілих чисел, таких, що числа Фібоначчі для цих індексів дорівнюють n і жодне два суміжних цілих числа не є частиною цього набору)

Зокрема, представництво Зекендорфа унікальне. Ось кілька прикладів представлень Зекендорфа:

Z (0) = ∅ (порожній набір)
Z (1) = {1}
Z (2) = {2}
Z (3) = {3} ({1, 2} - не представлення Зеккендорфа з 3)
Z (10) = {5, 2}
Z (100) = {3, 5, 10}

У цьому виклику представлення Zeckendorf кодуються як бітові набори, де найменший значущий біт являє собою 1частину набору тощо. Ви можете припустити, що представлення Zeckendorf і вхідного, і вихідного даних вписуються в 31 біт.

Ваше завдання - обчислити Z ( n + m ), задані Z ( n ) і Z ( m ). Виграє рішення з найменшою довжиною в октетах.

Ви можете знайти довідкову реалізацію, написану в ANSI C тут . Він також може бути використаний для генерування представлень Зекендорфа або для обчислення числа зі свого представлення Зекендорфа.

Ось кілька пар зразків введення та виведення, де перші два стовпці містять вхід, а третій стовпець містить вихід:

73865           9077257         9478805
139808          287648018       287965250
34              279004309       279004425
139940          68437025        69241105
272794768       1051152         273846948
16405           78284865        83888256
9576577         4718601         19013770
269128740       591914          270574722
8410276         2768969         11184785
16384           340             16724

4
Чи можете ви, будь ласка, розробити введення / вихід?
flawr

@flawr Погляньте на реалізовану посилання. Ви можете використовувати його для створення власного зразка.
FUZxxl

3
Буду радий, якщо ви зможете тут зафіксувати саме те, що ви хочете, і надати кілька прикладів, як я, і, можливо, інші теж занадто не володіють мовою C.
flawr

Я не згоден з аргументом унікальності. Оскільки послідовність Фібоначчі починається з 1, 1, 2, ви можете чітко розкласти 3 на F0 + F2 = 1 + 2 = 3. F0 і F2 не є суміжними.
orlp

1
@orlp Послідовність Фібоначчі, визначена тут, починається з F1 = 1 і F2 = 2. Тож те, як я його прочитав, F0 з вашого визначення не є частиною послідовності, що використовується тут.
Рето Коради

Відповіді:


5

К (нг / к) , 45 43 42 41 байт

{2/<':(+/F@&+/'|2\x){y!x}\|F:64(+':1,)/0}

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

@ Алгоритм Bubbler

{ } функція з аргументом x

64( )/0 зробити 64 рази, використовуючи 0 в якості початкового значення:

  • 1, наперед 1

  • +': додайте кожен попередній (перший елемент залиште недоторканим)

F:призначити Fдля "послідовності полів"

| зворотний

(.. ){y!x}\.. починаючи зі значення ліворуч, обчислюйте сукупні залишки (зліва направо) для списку праворуч. значення зліва - це звичайна сума входів без подання zeckendorf:

  • 2\xдвійкове кодування входів. це буде матриця nbits-by-2

  • | зворотний

  • +/' суму кожного

  • &де 1s? - перелік індексів. якщо є 2s, відповідний індекс повторюється двічі.

  • F@ індексація масиву в F

  • +/ сума

<': менше, ніж кожен попередній (перший результат завжди буде фальсифікованим)

2/ двійкове декодування


10

CJam, 76 74 70 63 59 байт

2q~{32{2\#I&},}fI+32_,*{WUer$Kf-[UU]/[-2X]*2,/2a*Kf+}fKf#1b

Спробуйте в Інтернеті в інтерпретаторі CJam або перевірити всі тестові випадки одразу .

Ідея

Почнемо з визначення незначної зміни послідовності у питанні:

G -2 = 0
G -1 = 1
G k = G k-1 + G k-2 всякий раз, коли k є негативним цілим числом

Таким чином, біт 0 (LSB) вхідного або вихідного масивів бітів відповідає номеру Фібоначчі G 0 і, взагалі, біту k до G k .

Тепер ми заміняємо кожен набір бітів у Z (n) та Z (m) на індекс, який він кодує.

Наприклад, вхід 532 10 = 1000010100 2 перетворюється на [2 4 9] .

Це дає два масиви цілих чисел, які ми можемо об'єднати, щоб утворити одне ціле.

Наприклад, якщо n = m = 100 , то результат A: = [2 4 9 2 4 9] .

Якщо кожну k в A замінити G на G k і додати результати, отримаємо n + m = 200 , тому A - це спосіб розкласти 200 на числа Фібоначчі, але, звичайно, не той, що з теореми Зеккендорфа.

Маючи на увазі, що G k + G k + 1 = G k + 2 і G k + G k = G k + G k-1 + G k-2 = G k + 1 + G k-2 , ми можемо підміняти послідовно і дублюються індекси іншими (а саме (k, k + 1) на k + 2 і (k, k) на (k + 1, k - 2) ), повторюючи ці заміни знову і знову, поки не буде досягнуто представлення Зекендорфа. 1

Необхідно взяти окремий випадок для отриманих негативних показників. Оскільки G -2 = 0 , індекс -2 можна просто ігнорувати. Також G -1 = 0 = G 0 , тому будь-який результат -1 повинен бути замінений на 0 .

Для нашого прикладу A ми отримуємо наступні (відсортовані) подання, останнє - представлення Зекендорфа.

[2 2 4 4 9 9] → [0 3 4 4 9 9] → [0 5 4 9 9] → [0 6 9 9] → [0 6 7 10] → [0 8 10]

Нарешті, ми перетворюємо назад з масиву цілих чисел у бітовий масив.

Код

2             e# Push a 2 we'll need later.
q~            e# Read and evaluate the input.
{             e# For each integer I in the input:
  32{         e#   Filter [0 ... 31]; for each J:
    2\#       e#     Compute 2**J.
    I&        e#     Compute its logical AND with I.
  },          e#   Keep J if the result in truthy (non-zero).
}fI           e#
+             e# Concatenate the resulting arrays.
32_,*         e# Repeat [0 ... 31] 32 times.
{             e# For each K:
  WUer        e#   Replace -1's with 0's.
  $           e#   Sort.
  Kf-         e#   Subtract K from each element.
  [UU]/[-2X]* e#   Replace subarrays [0 0] with [-2 1].
  2,/2a*      e#   Replace subarrays [0 1] with [2].
  Kf+         e#   Add K to each element.
}fK           e#
f#            e# Replace each K with 2**K.
1b            e# Cast all to integer (discards 2**-2) and sum.

1 Спроба впровадження заміняється 32 рази і не перевіряє, чи дійсно було досягнуто представлення Зекендорфа. У мене немає офіційного підтвердження того, що цього достатньо, але я перевірив усі можливі суми 15-бітових представлень (чиї подання сум вимагають до 17 біт) і 6 повторень було достатньо для всіх. У будь-якому випадку збільшити кількість повторень до 99 можливо без збільшення кількості байтів, але це призведе до каліки.


10

APL (Dyalog Extended) , 39 байт

1↓⍧|/⌽(+/g[⍸⌽+/⊤⎕]),↑,\⌽g←(2+/,)⍣38⍨⍳2

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

Змінився на повну програму, взявши один аргумент довжиною 2, а також змінив генератор Фібоначчі. Дякуємо @ngn за безліч ідей.

Використовує ⎕IO←0так, що ⍳2оцінює до 0 1.

Генератор Фібоначчі (новий)

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

(2+/,)⍣38⍨⍳2
 0 1 ((2+/,)⍣38) 0 1

Step 1
0 1 (2+/,) 0 1
 2+/ 0 1 0 1
 (0+1) (1+0) (0+1)  2+/ evaluates sums for moving window of length 2
 1 1 1

Step 2
0 1 (2+/,) 1 1 1
 2+/ 0 1 1 1 1
 1 2 2 2

Step 3
0 1 (2+/,) 1 2 2 2
 2+/ 0 1 1 2 2 2
 1 2 3 4 4

Зекендорф до рівнини (частково)

⍸⌽+/⊤⎕
        Take input from stdin, must be an array of 2 numbers
        Convert each number to base 2; each number is mapped to a column
  +/     Sum in row direction; add up the counts at each digit position
        Reverse
        Convert each number n at index i to n copies of i

APL (Dyalog Extended) , 47 байт

g1↓(1,+\⍤,)⍣201
{⊥1↓⍧|/⌽⍵,↑,\⌽g}+⍥{+/g[⍸⌽⊤⍵]}

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

Змінено частину 1 попередньої відповіді для повторного використання чисел Фібоначчі. Крім того, киньте дублікат 1, щоб зберегти деякі байти в інших місцях.

Частина 1 (нова)

{+/g[⍸⌽⊤⍵]}
       ⊤⍵     Argument to binary digits
     ⍸⌽       Reverse and convert to indices of ones
   g[    ]    Index into the Fibonacci array of 1,2,3,5,...
 +/           Sum

APL (Dyalog Extended) , 52 байти

{⊥1↓¯1↓⍧|/⌽⍵,↑,\⌽(1,+\⍤,)⍣201}+⍥({+∘÷⍣(⌽⍳≢⊤⍵)⍨1}⊥⊤)

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

Як це працює

Немає фантазійного алгоритму для додавання в Zeckendorf, оскільки APL не відомий для роботи з окремими елементами в масиві. Натомість я пішов перетворити два входи із Зекендорфа в прості цілі числа, додати їх та перетворити їх назад.

Частина 1: Зекендорф до простого числа

{+∘÷⍣(⌽⍳≢⊤⍵)⍨1}⊥⊤   Zeckendorf to plain integer
                   Convert the input to array of binary digits (X)
{    (  ≢⊤⍵)  }     Take the length L of the binary digits and
      ⌽⍳              generate 1,2..L backwards, so L..2,1
{+∘÷⍣(     )⍨1}     Apply "Inverse and add 1" L..2,1 times to 1
                    The result looks like ..8÷5 5÷3 3÷2 2 (Y)
                   Mixed base conversion of X into base Y

Base |             Digit value
-------------------------------
13÷8 | (8÷5)×(5÷3)×(3÷22 = 8
 8÷5 |       (5÷3)×(3÷22 = 5
 5÷3 |             (3÷22 = 3
 3÷2 |                   2 = 2
 2÷1 |                   1 = 1

Частина 2: Додайте два прості цілі числа

+⍥z2i   Given left and right arguments,
          apply z2i to each of them and add the two

Частина 3: Перерахуйте суму назад в Зекендорф

"Ви можете припустити, що представлення Zeckendorf і вхідного, і вихідного вкладається в 31 біт" було досить зручно.

{⊥1↓¯1↓⍧|/⌽⍵,↑,\⌽(1,+\⍤,)⍣201}   Convert plain integer N to Zeckendorf
                 (1,+\⍤,)⍣201    First 41 Fibonacci numbers starting with two 1's
                ⌽                ⍝ Reverse
             ↑,\                 ⍝ Matrix of prefixes, filling empty spaces with 0's
          ⌽⍵,                     Prepend N to each row and reverse horizontally
        |/                        Reduce by | (residue) on each row (see below)
                                 Nub sieve; 1 at first appearance of each number, 0 otherwise
  1↓¯1                           Remove first and last item
                                 Convert from binary digits to integer

Генератор Фібоначчі

(1,+\⍤,)⍣201
 1 ((1,+\⍤,)⍣20) 1   Expand 
 Apply 1 (1,+\⍤,) x 20 times to 1

First iteration
1(1,+\⍤,)1
 1,+\1,1   Expand the train
 1,1 2     +\ is cumulative sum
 1 1 2     First three Fibonacci numbers

Second iteration
1(1,+\⍤,)1 1 2
 1,+\1,1 1 2   Expand the train
 1 1 2 3 5     First five Fibonacci numbers

20   ... Repeat 20 times

Це випливає із властивості чисел Фібоначчі: якщо Фібоначчі визначено як

F0=F1=1;n0,Fn+2=Fn+1+Fn

тоді

n0,i=0nFi=Fn+21

Таким чином, сукупна сума (масив Фібоначчі, передбачуваний 1) стає . Потім я знову додаю 1, щоб отримати звичайний масив Фібоначчи, починаючи з індексу 0.1,F0,,FnF1,,Fn+2

Цифри Фібоначчі до Зекендорфа

Input: 7, Fibonacci: 1 1 2 3 5 8 13

Matrix
0 0 0 0 0 0 13 7
0 0 0 0 0 8 13 7
0 0 0 0 5 8 13 7
0 0 0 3 5 8 13 7
0 0 2 3 5 8 13 7
0 1 2 3 5 8 13 7
1 1 2 3 5 8 13 7

Reduction by residue (|/)
- Right side always binds first.
- x|y is equivalent to y%x in other languages.
- 0|y is defined as y, so leading zeros are ignored.
- So we're effectively doing cumulative scan from the right.
0 0 0 0 0 0 13 7 → 13|7 = 7
0 0 0 0 0 8 13 7 →  8|7 = 7
0 0 0 0 5 8 13 7 →  5|7 = 2
0 0 0 3 5 8 13 7 →  3|2 = 2
0 0 2 3 5 8 13 7 →  2|2 = 0
0 1 2 3 5 8 13 7 →  1|0 = 0
1 1 2 3 5 8 13 7 →  1|0 = 0
Result: 7 7 2 2 0 0 0

Nub sieve (⍧): 1 0 1 0 1 0 0
1's in the middle are produced when divisor  dividend
(so it contributes to a Zeckendorf digit).
But the first 1 and last 0 are meaningless.

Drop first and last (1↓¯1↓): 0 1 0 1 0
Finally, we apply base 2 to integer (⊥) to match the output format.

6

Хаскелл, 325 396 байт

EDIT: нова версія:

s f[]=[]
s f l=f l
x((a:b):(c:d):(e:r))=x(b:d:(a:e):r)
x(a:b:((c:d:e):r))=x((c:a):b:e:((d:s head r):s tail r))
x[]=[]
x(a:r)=a:x r
w l|x l/=l=w.x$l|True=l
l=length
t n x=take n$repeat x
j 0=[]
j n=t(mod(n)2)1:j(div(n)2)
i n=[[],[]]++j n++t(32-(l$j n))[]
u[]=0
u(a:r)=2*u r+l a
o(_:a:r)=u r+l a
z a b=o$w$zipWith(++)(i a)(i b)

z виконує роботу.


Деякі речі можна скоротити відразу - наприклад, функція має найвищий пріоритет, тому ви можете позбутися батьків навколо функціональних додатків, а також охоронцям також не потрібні батьки - охоронці зупиняються там, де =є, тому батькам там не потрібно. і т. д. і так далі, і зауважте, що :асоціюється праворуч, і ви можете вирізати там деякі. Але, все-таки, вітаю! Виглядає дуже складно. Не можу чекати, щоб зрозуміти, як це працює!
гордий haskeller

@proudhaskeller Марно складне, хоча дивіться мою редакцію. Чи повинен я пояснити основну ідею? Це може бути краще іншим способом, але я спробував спочатку зробити якомога більше узгодження шаблонів. А, під батьками ви маєте на увазі круглі дужки: гольф, що!
Лейф Віллерц

chillax, це твій перший раз тут. Якщо ви будете довго залишатися, ви зросте набагато краще. Не забудьте перевірити питання щодо підказок щодо гольфу Haskell для ознайомлення з кодом golf.stackexchange.com/questions/19255/…
гордий haskeller

Прийшла редакція @proudhaskeller ...
Leif Willerts

4

ES6, 130 байт

(n,m)=>{for(a={},s=0,i=x=y=1;i<<1;i+=i,z=y,y=x,x+=z)s+=((n&i)+(m&i))/i*(a[i]=x);for(r=0;i;i>>>=1)s>=a[i]?(s-=a[i],r|=i):0;return r}

Спочатку я намагався обчислити суму на місці (ефективно за принципами впровадження CJam), але у мене не вистачало темпорарій, тому я просто перетворив числа на реальні цілі числа і назад.

(Так, я, певно, можу зберегти байт за допомогою eval.)


1

Рубі , 85 73 65 байт

->*a{r=(0..2*a.sum).select{|r|r^r*2==r*3};r[a.sum{|w|r.index w}]}

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

Як?

Спочатку знайдіть верхню межу для закодованої суми: (a + b) * 2 нормально.

Тепер відфільтруйте всі не zeckendorf числа з (0..limit).

У нас є таблиця пошуку, звідси вона під гору.


1

Python 3, 207 байт

def s(n):
 p=1
 while n>=2*p:
  p*=2
 return n if n<=p else s(n+p//2)if n>=3*p/2 else s(m)if (m:=s(n-p)+p)!= n else n
a=lambda n,m:(b:=n&m)>-1 and s(a(a(a(s((n|m)-b%4),b//4*2),b//4),b%4*2+b%4//2))if m else n

Спробуйте в Інтернеті! (Перевірте всі тестові випадки)

Пояснення

Ця програма безпосередньо маніпулює бінарними перекладами представлень Зекендорфа. Функція a(n,m)виконує основні обчислення і s(n)є хелперною функцією, яка позбавляється від сусідніх чисел, що містяться в поданні Зекендорфа.

Почнемо з функції s(n)(розширеної для наочності):

def s(n): 
    p=1                  #This finds the highest digit of the binary form of n.
    while n>=2*p:
        p*=2
    if n<=p:             #If n is a power of two (i.e, our number is already a Fibonnaci number)...
        return n         #Then return it normally.  This also works for zero. (A)
    if n>=3*p/2:         #If n's first digit is followed by a 1 (i.e, it starts with 11X)
        return s(n+p//2) #Then replace that with 100X (B)
    m = s(n-p)+p         #Otherwise, apply s to the rest of the number (C)
    if m==n:             #If this is out final result, we're done! (D)
        return n
    return s(m)          #Otherwise, reapply it. (E)

Наприклад, число 107 ( 1101011у двійковій формі, що представляє 1 + 2 + 5 + 13 + 21 = 42), проходить такий процес:

1+2+5+13+21 [1101011] -> 1+2+5+34 [10001011] (B)
1+2+5+34 [10001011] (C)
 1+2+5 [1011] (C)
  1+2 [11] -> 3 [100] (B)
 ->3+5 [1100] (A/E)
 (E):  3+5 [1100] -> 8 [10000] (B)
->8+34 [10010000] (A/E)
(E): 8+34 [10010000] (C)
->8+34 [10010000] (A/E)

Спробуйте в Інтернеті! (з детальним результатом)

Ось розширена версія a(n,m):

def a(n,m):
    if m==0:
        return n
    b=n&m
    t=s((n|m)-b%4)              #(A)
    t=a(t,b//4*2)               #(B)
    t=a(t,b//4)                 #(C)
    return s(a(t,b%4*2+b%4//2)) #(D)

Ця функція перетворює два подання Зекендорфа на чотири двійкові числа, які легше поєднувати. Рядок (А) є порозрядним АБО двох двійкових представлень Зекендорфа - вони відповідають одній копії кожного числа Фібоначчі в будь-якій групі. (B) і (C) - порозрядні AND з двох чисел, зміщених праворуч 1 і 2 рази відповідно. Ми знаємо, що коли відповідні числа Фібоначчі для (B) і (C) складені разом, вони будуть еквівалентними порозрядним AND нашим nі mтому F (n) = F (n-1) + F (n-2) .

Наприклад, скажімо, що у нас є двійкові числа n = 101001 (що відповідають 1 + 5 + 13) і m = 110110 (2 + 3 + 8 + 13). Тоді у нас буде (A) = 111111 (1 + 2 + 3 + 5 + 8 + 13), який перетворюється на 1010100 (3 + 8 + 21) за нашою функцією s, (B) = 10000 (8), і ( В) = 1000 (5). Ми можемо перевірити, що (1 + 5 + 13) + (2 + 3 + 8 + 13) = (3 + 8 + 21) + (8) + (5) = 45. Цей процес повторюється з ((3 + 8 + 21) + (8)) + (5) = ((3 + 8 + 21) + (5) + (3)) + (5) тощо.

Одна з складнощів цієї системи полягає в тому, що вона не працює для цифр 1 і 2 Фібоначчі, оскільки вони не підкоряються властивості F(n)=F(n-1)+F(n-2)(вони найнижчі два числа)! Через це, коли 1 або 2 міститься в обох, nі mвони видаляються з A, B і C, то їх сума розміщується в D під властивістю, що 1 + 1 = 2 і 2 + 2 = 1 + 3. Наприклад, якщо додати 1 + 3 (101) + 1 + 3 + 5 (1101), отримаємо:

(А): 3 + 5 (1100) = 8 (10000)

(B): 2 (10)

(С): 1 (1)

(D): 2 (10)

Зауважте, що 3 і 5 були поміщені в A, дублікат 3 розділили на 2 + 1 у B і C, а дублікати 1 видалили з A, B і C, склали разом і поклали в D. Аналогічно, якщо ми додаємо 2 + 3 (110) + 2 + 3 + 5 (1110), отримуємо:

(А): 3 + 5 (1100) = 8 (10000)

(B): 2 (10)

(С): 1 (1)

(D): 1 + 3 (101)

Спробуйте в Інтернеті! (з детальним результатом)


0

Мова Вольфрама (Mathematica) , 218 байт

Fold[#+##&,Total@PadLeft@IntegerDigits[#,2]//.{{p=n_/;n>1,r=y___}:>{0,n,y},{q=x___,i_,p,j_,k_,r}:>{x,i+1,n-2,j,k+1,y},{q,i_,p,j_}:>{x,i+1,n-2,j+1},{q,i_,p}:>{x,i+1,n-2},{1,1,r}:>{1,0,0,y},{q,i_,1,1,r}:>{x,i+1,0,0,y}}]&

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

Просто узгодження шаблону.

Безголівки:

FromDigits[Total@PadLeft@IntegerDigits[#, 2] //.
   {{n_ /; n > 1, y___} :> {0, n, y},
    {x___, i_, n_ /; n > 1, j_, k_, y___} :> {x, i + 1, n - 2, j, k + 1, y},
    {x___, i_, n_ /; n > 1, j_} :> {x, i + 1, n - 2, j + 1},
    {x___, i_, n_ /; n > 1} :> {x, i + 1, n - 2},
    {1, 1, y___} :> {1, 0, 0, y},
    {x___, i_, 1, 1, y___} :> {x, i + 1, 0, 0, y}}, 2] &
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.