Суммирование в представлении Цекендорфа

14

Теорема Цекендорфа показывает, что каждое положительное целое число может быть однозначно представлено в виде суммы несмежных чисел Фибоначчи. В этом задании вы должны вычислить сумму двух чисел в представлении Цекендорфа.


Пусть F n будет n-м числом Фибоначчи, где

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

Представление Цекендорфа Z ( n ) неотрицательного целого числа n представляет собой набор натуральных чисел, таких что

п = Σ я ∈ Z , ( п ) Р я   и
я ∈ Z , ( п ) я + 1 ∉ Z ( п ).

(в прозе: представление Цекендорфа числа n представляет собой набор натуральных чисел, таких, что числа Фибоначчи для этих индексов суммируют до n, и никакие два соседних целых числа не являются частью этого набора)

Примечательно, что представление Zeckendorf является уникальным. Вот несколько примеров для представлений Zeckendorf:

Z (0) = ∅ (пустое множество)
Z (1) = {1}
Z (2) = {2}
Z (3) = {3} ({1, 2} не является представлением Цекендорфа 3)
Z (10) = {5, 2}
Z (100) = {3, 5, 10}

В этой задаче представления Цекендорфа кодируются как наборы битов, где младший значащий бит представляет собой, если он 1является частью набора, и т. Д. Можно предположить, что представления Цекендорфа как входных, так и выходных данных укладываются в 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
FUZxxl
источник
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

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

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

Попробуйте онлайн!

Алгоритм Бубблера

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

64( )/0 сделать 64 раза, используя 0 в качестве начального значения:

  • 1, подготовить 1

  • +': добавить каждый предыдущий (оставить первый элемент без изменений)

F:назначить Fдля "последовательности Фибоначчи"

| обеспечить регресс

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

  • 2\xдвоичное кодирование входов. это будет матрица размером 2 бит на 2

  • | обеспечить регресс

  • +/' суммировать каждый

  • &где 1с? - список показателей. если есть любые 2, соответствующий индекс повторяется дважды.

  • 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 (младший бит) из входных битовых массивов или выход соответствует числу Фибоначчи G 0 и, в общем, бит к к G к .

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

Например, вход 532 10 = 1000010100 2 преобразуется в [2 4 9] .

Это дает два массива целых чисел, которые мы можем объединить в один.

Например, если n = m = 100 , результат будет A: = [2 4 9 2 4 9] .

Если мы заменим каждое k в A на 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: Zeckendorf для простого целого числа

{+∘÷⍣(⌽⍳≢⊤⍵)⍨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: Преобразование суммы обратно в Цекендорф

«Можно предположить, что представления Цекендорфа как входных, так и выходных данных помещаются в 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,Σязнак равно0NFязнак равноFN+2-1

Итак, накопленная сумма 1,F0,,FN (Массив Фибоначчи с добавлением 1) становится F1,,FN+2, Затем я снова добавляю 1, чтобы получить обычный массив Фибоначчи, начинающийся с индекса 0.

Цифры Фибоначчи в Цекендорф

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 байтов

РЕДАКТИРОВАТЬ: новая версия:

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 Бесполезно сложно, хотя, см. мое редактирование. Должен ли я объяснить основную идею? Может быть, лучше и по-другому, но сначала я старался сделать как можно больше совпадений с образцами. Ах, под родителями ты подразумеваешь скобки: игра в гольф!
Лейф Виллертс
Чиллакс, это твой первый раз здесь. Если вы останетесь надолго, вы станете намного лучше. Обязательно ознакомьтесь с вопросом о советах по
гордый haskeller
@proudhaskeller редактировать прибыл ...
Лейф Виллертс
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 в порядке.

Теперь отфильтруйте все числа не-Зеккендорфа из (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)

Эта функция преобразует два представления Цекендорфа в четыре двоичных числа, которые легче объединить. Линия (A) - это побитовое ИЛИ двух двоичных представлений Цекендорфа - они соответствуют одной копии каждого числа Фибоначчи в любой группе. (B) и (C) - побитовое И двух чисел, сдвинутых вправо 1 и 2 раза соответственно. Мы знаем, что когда соответствующие числа Фибоначчи для (B) и (C) складываются вместе, они будут эквивалентны поразрядному И нашего 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)

(В): 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)

(В): 2 (10)

(С): 1 (1)

(D): 1 + 3 (101)

Попробуйте онлайн! (с подробным выводом)

Мэдисон Сильвер
источник
0

Wolfram Language (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}}]&

Попробуйте онлайн!

Просто сопоставление с образцом.

Ungolfed:

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] &
alephalpha
источник