Sommatoria sotto la rappresentanza di Zeckendorf


14

Il teorema di Zeckendorf mostra che ogni numero intero positivo può essere rappresentato in modo univoco come una somma di numeri di Fibonacci non adiacenti. In questa sfida, devi calcolare la somma di due numeri nella rappresentazione di Zeckendorf.


Sia F n il n -esimo numero di Fibonacci dove

F 1 = 1,
F 2 = 2 e
per tutti k > 2, F k = F k - 1 + F k - 2 .

La rappresentazione Z ( n ) di Zeckendorf di un numero intero non negativo n è un insieme di numeri interi positivi tali che

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

(in prosa: la rappresentazione di Zeckendorf di un numero n è un insieme di numeri interi positivi in ​​modo tale che i numeri di Fibonacci per questi indici si sommino fino a n e che non vi siano due numeri interi adiacenti)

In particolare, la rappresentazione di Zeckendorf è unica. Ecco alcuni esempi di rappresentazioni di Zeckendorf:

Z (0) = ∅ (l'insieme vuoto)
Z (1) = {1}
Z (2) = {2}
Z (3) = {3} ({1, 2} non è la rappresentazione Zeckendorf di 3)
Z (10) = {5, 2}
Z (100) = {3, 5, 10}

In questa sfida, le rappresentazioni di Zeckendorf sono codificate come set di bit in cui il bit meno significativo rappresenta se 1fa parte del set, ecc. Si può supporre che le rappresentazioni di Zeckendorf sia in ingresso che in uscita si adattino a 31 bit.

Il tuo compito è calcolare Z ( n + m ) dato Z ( n ) e Z ( m ). Vince la soluzione con la lunghezza più corta in ottetti.

Puoi trovare un'implementazione di riferimento scritta in ANSI C qui . Può anche essere usato per generare rappresentazioni Zeckendorf o calcolare un numero dalla sua rappresentazione Zeckendorf.

Ecco alcune coppie di input e output di esempio, in cui le prime due colonne contengono l'input e la terza colonna contiene l'output:

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
Potresti per favore elaborare l'input / output?
flawr

@flawr Dai un'occhiata all'implementazione di riferimento fornita. Puoi usarlo per generare il tuo input di esempio.
FUZxxl,

3
Sarei felice se potessi documentare qui esattamente quello che vuoi e fornire alcuni esempi, come lo sono io, e forse anche altri, non fluente in C.
flawr

Non sono d'accordo con l'argomento unicità. Poiché la sequenza di Fibonacci inizia con 1, 1, 2, puoi chiaramente scomporre 3 in F0 + F2 = 1 + 2 = 3. F0 e F2 non sono adiacenti.
orlp,

1
@orlp La sequenza di Fibonacci qui definita inizia con F1 = 1 e F2 = 2. Quindi il modo in cui l'ho letto, F0 dalla tua definizione non fa parte della sequenza usata qui.
Reto Koradi,

Risposte:


5

K (ngn / k) , 45 43 42 41 byte

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

Provalo online!

Algoritmo di @ Bubbler

{ } funzione con argomento x

64( )/0 fare 64 volte, usando 0 come valore iniziale:

  • 1, anteporre 1

  • +': aggiungi ogni precedente (lascia intatto il primo elemento)

F:assegnare a Fper "sequenza fibonacci"

| inversione

(.. ){y!x}\.. iniziando con il valore a sinistra, calcola i resti cumulativi (da sinistra a destra) per l'elenco a destra. il valore a sinistra è la semplice somma degli input senza rappresentazione zeckendorf:

  • 2\xbinario codifica gli ingressi. questa sarà una matrice nbits-by-2

  • | inversione

  • +/' sommare ciascuno

  • &dove sono gli 1? - elenco di indici. se sono presenti 2 secondi, l'indice corrispondente viene ripetuto due volte.

  • F@ indicizzazione dell'array in F

  • +/ somma

<': meno di ogni precedente (il primo del risultato sarà sempre falso)

2/ decodifica binaria


10

CJam, 76 74 70 63 59 byte

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

Provalo online nell'interprete CJam o verifica tutti i casi di test contemporaneamente .

Idea

Iniziamo definendo una variazione minore della sequenza nella domanda:

G -2 = 0
G -1 = 1
G k = G k-1 + G k-2 ogni volta che k è un numero intero non negativo

In questo modo, il bit 0 (LSB) delle matrici di bit in ingresso o in uscita corrisponde al numero di Fibonacci G 0 e, in generale, ai bit da k a G k .

Ora sostituiamo ogni bit impostato in Z (n) e Z (m) con l'indice che codifica.

Ad esempio, l'ingresso 532 10 = 1000010100 2 viene trasformato in [2 4 9] .

Questo produce due matrici di numeri interi, che possiamo concatenare per formare un singolo.

Ad esempio, se n = m = 100 , il risultato è A: = [2 4 9 2 4 9] .

Se sostituiamo ogni k in A con G k e aggiungiamo i risultati, otteniamo n + m = 200 , quindi A è un modo per scomporre 200 in numeri di Fibonacci, ma certamente non quello dal teorema di Zeckendorf.

Tenendo presente che G k + G k + 1 = G k + 2 e G k + G k = G k + G k-1 + G k-2 = G k + 1 + G k-2 , possiamo sostituire consecutivamente e indici duplicati da altri (ovvero, (k, k + 1) per k + 2 e (k, k) per (k + 1, k - 2) ), ripetendo ripetutamente tali sostituzioni fino al raggiungimento della rappresentazione di Zeckendorf. 1

Caso speciale deve essere preso per gli indici negativi risultanti. Poiché G -2 = 0 , l'indice -2 può essere semplicemente ignorato. Inoltre, G -1 = 0 = G 0 , quindi ogni -1 risultante deve essere sostituito da 0 .

Per il nostro esempio A , otteniamo le seguenti rappresentazioni (ordinate), l'ultima è la rappresentazione di Zeckendorf.

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

Infine, riconvertiamo l'array di numeri interi in array di bit.

Codice

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 L'implementazione tenta di sostituire 32 volte e non verifica se la rappresentazione Zeckendorf è stata effettivamente raggiunta. Non ho una prova formale che questo sia sufficiente, ma ho testato tutte le possibili somme di rappresentazioni a 15 bit (le cui rappresentazioni di somme richiedono fino a 17 bit) e 6 ripetizioni sono state sufficienti per tutte. In ogni caso, è possibile aumentare il numero di ripetizioni a 99 senza aumentare il conteggio dei byte, ma comprometterebbe le prestazioni.


10

APL (Dyalog Extended) , 39 byte

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

Provalo online!

Modificato in un programma completo prendendo un argomento di lunghezza 2, e anche cambiato il generatore di Fibonacci. Grazie a @ngn per molte idee.

Utilizza in ⎕IO←0modo che ⍳2valuti 0 1.

Generatore di Fibonacci (nuovo)

Si noti che gli ultimi due numeri sono inaccurati, ma non cambia l'output del programma.

(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

Zeckendorf a pianura (parziale)

⍸⌽+/⊤⎕
        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 byte

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

Provalo online!

Modificata la parte 1 della risposta precedente per riutilizzare i numeri di Fibonacci. Inoltre, rilasciare il duplicato 1 per salvare alcuni byte in altri punti.

Parte 1 (nuova)

{+/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 byte

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

Provalo online!

Come funziona

Nessun algoritmo elaborato da aggiungere in Zeckendorf perché APL non è noto per il funzionamento su singoli elementi in un array. Invece, sono andato avanti per convertire i due input da Zeckendorf in interi semplici, aggiungerli e riconvertirli.

Parte 1: Zeckendorf al numero intero semplice

{+∘÷⍣(⌽⍳≢⊤⍵)⍨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

Parte 2: aggiungi due interi semplici

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

Parte 3: riconvertire la somma in Zeckendorf

"Si può presumere che le rappresentazioni di Zeckendorf sia in ingresso che in uscita si adattino a 31 bit" è stato molto utile.

{⊥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

Il generatore di Fibonacci

(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

Ciò deriva dalla proprietà dei numeri di Fibonacci: se Fibonacci è definito come

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

poi

n0,i=0nFi=Fn+21

1,F0,,FnF1,,Fn+2

Cifre da Fibonacci a Zeckendorf

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

Haskell, 325 396 byte

EDIT: nuova versione:

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 fa il lavoro.


Alcune cose possono essere immediatamente accorciate - ad esempio la funzione ha la precedenza più alta, quindi puoi liberarti dei genitori dalle applicazioni delle funzioni e anche le guardie non hanno bisogno dei genitori - le guardie si fermano dove si =trova, quindi i genitori non sono necessari , e così via e così via, e nota che si :associa a destra e puoi tagliare un po 'lì. Ma comunque complimenti! Sembra molto complicato. Non vedo l'ora di capire come funziona!
orgoglioso haskeller il

@proudhaskeller Inutilmente complicato, vedi la mia modifica. Devo spiegare l'idea di base? Potrebbe essere meglio in un altro modo, ma all'inizio ho provato a fare il maggior numero possibile di pattern matching. Ah, per genitori intendi le parentesi: questo è il golf!
Leif Willerts,

Chillax, è la tua prima volta qui. Se rimani a lungo, crescerai molto meglio. Assicurati di controllare la domanda dei suggerimenti sul golf di Haskell per alcune informazioni su codegolf.stackexchange.com/questions/19255/…
orgoglioso haskeller il

La modifica di @proudhaskeller è arrivata ...
Leif Willerts

4

ES6, 130 byte

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

Inizialmente ho provato a calcolare la somma sul posto (effettivamente lungo le linee dell'implementazione di CJam) ma ho continuato a rimanere senza i provvisori, quindi ho appena convertito i numeri in e viceversa da numeri interi reali.

(Sì, probabilmente posso salvare un byte usando eval.)


1

Rubino , 85 73 65 byte

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

Provalo online!

Come?

Per prima cosa ottieni un limite superiore per la somma codificata: (a + b) * 2 è ok.

Ora filtra tutti i numeri non zeckendorf da (0..limit).

Abbiamo una tabella di ricerca, è in discesa da qui.


1

Python 3, 207 byte

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

Provalo online! (Verifica tutti i casi di test)

Spiegazione

Questo programma manipola direttamente le traduzioni binarie delle rappresentazioni di Zeckendorf. La funzione a(n,m)esegue i calcoli principali ed s(n)è una funzione di supporto che elimina i numeri adiacenti contenuti nella rappresentazione di Zeckendorf.

Cominciamo con la funzione s(n)(espansa per chiarezza):

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)

Ad esempio, il numero 107 ( 1101011in binario, che rappresenta 1 + 2 + 5 + 13 + 21 = 42), viene sottoposto al seguente processo:

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)

Provalo online! (s con output dettagliato)

Ecco una versione estesa di 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)

Questa funzione converte le due rappresentazioni di Zeckendorf in quattro numeri binari che sono più facili da combinare. La riga (A) è l'OR bit a bit delle due rappresentazioni binarie di Zeckendorf, che corrispondono a una copia di ciascun numero di Fibonacci in entrambi i gruppi. (B) e (C) sono AND bit a bit dei due numeri spostati a destra 1 e 2 volte, rispettivamente. Sappiamo che quando i corrispondenti numeri di Fibonacci per (B) e (C) vengono sommati, saranno equivalenti all'AND bit a bit del nostro ne mperché F (n) = F (n-1) + F (n-2) .

Ad esempio, supponiamo che abbiamo i numeri binari n = 101001 (corrispondente a 1 + 5 + 13) e m = 110110 (2 + 3 + 8 + 13). Quindi avremo (A) = 111111 (1 + 2 + 3 + 5 + 8 + 13), che viene convertito in 1010100 (3 + 8 + 21) dalla nostra funzione s, (B) = 10000 (8) e ( C) = 1000 (5). Possiamo verificare che (1 + 5 + 13) + (2 + 3 + 8 + 13) = (3 + 8 + 21) + (8) + (5) = 45. Questo processo si ripete con ((3 + 8 + 21) + (8)) + (5) = ((3 + 8 + 21) + (5) + (3)) + (5), ecc.

L'unica difficoltà con questo sistema è che non funziona con i numeri 1 e 2 di Fibonacci, poiché non obbediscono alla proprietà F(n)=F(n-1)+F(n-2)(sono i due numeri più bassi)! Per questo motivo, ogni volta che 1 o 2 sono contenuti in entrambi ne m, vengono rimossi da A, B e C, quindi la loro somma viene posizionata in D sotto la proprietà che 1 + 1 = 2 e 2 + 2 = 1 + 3. Ad esempio, se aggiungiamo 1 + 3 (101) + 1 + 3 + 5 (1101), otteniamo:

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

(B): 2 (10)

(C): 1 (1)

(D): 2 (10)

Si noti che 3 e 5 sono stati collocati in A, il duplicato 3 è stato diviso in 2 + 1 in B e C e i duplicati 1 sono stati rimossi da A, B e C, aggiunti insieme e inseriti in D. Allo stesso modo, se noi aggiungi 2 + 3 (110) + 2 + 3 + 5 (1110), otteniamo:

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

(B): 2 (10)

(C): 1 (1)

(D): 1 + 3 (101)

Provalo online! (a con output dettagliato)


0

Wolfram Language (Mathematica) , 218 byte

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

Provalo online!

Semplicemente il pattern matching.

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