Sommation sous représentation de Zeckendorf

14

Le théorème de Zeckendorf montre que chaque entier positif peut être représenté de manière unique comme une somme de nombres de Fibonacci non adjacents. Dans ce défi, vous devez calculer la somme de deux nombres dans la représentation de Zeckendorf.


Soit F n le n -ième nombre de Fibonacci où

F 1 = 1,
F 2 = 2 et
pour tout k > 2, F k = F k - 1 + F k - 2 .

La représentation Zeckendorf Z ( n ) d'un entier non négatif n est un ensemble d'entiers positifs tels que

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

(en prosa: la représentation de Zeckendorf d'un nombre n est un ensemble d'entiers positifs tels que les nombres de Fibonacci pour ces indices se résument à n et pas deux entiers adjacents font partie de cet ensemble)

Notamment, la représentation de Zeckendorf est unique. Voici quelques exemples de représentations de Zeckendorf:

Z (0) = ∅ (l'ensemble vide)
Z (1) = {1}
Z (2) = {2}
Z (3) = {3} ({1, 2} n'est pas la représentation de Zeckendorf de 3)
Z (10) = {5, 2}
Z (100) = {3, 5, 10}

Dans ce défi, les représentations Zeckendorf sont codées sous forme d' ensembles de bits où le bit le moins significatif représente si 1fait partie de l'ensemble, etc. Vous pouvez supposer que les représentations Zeckendorf de l'entrée et de la sortie tiennent sur 31 bits.

Votre tâche consiste à calculer Z ( n + m ) étant donné Z ( n ) et Z ( m ). La solution avec la longueur d'octets la plus courte l'emporte.

Vous pouvez trouver une implémentation de référence écrite en ANSI C ici . Il peut également être utilisé pour générer des représentations Zeckendorf ou calculer un nombre à partir de sa représentation Zeckendorf.

Voici quelques paires d'échantillons d'entrée et de sortie, où les deux premières colonnes contiennent l'entrée et la troisième colonne contient la sortie:

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
la source
4
Pourriez-vous s'il vous plaît élaborer l'entrée / sortie?
flawr
@flawr Veuillez consulter l'implémentation de référence fournie. Vous pouvez l'utiliser pour générer votre propre entrée d'échantillon.
FUZxxl
3
Je serais heureux si vous pouviez documenter ici exactement ce que vous voulez et fournir quelques exemples, comme je le suis, et peut-être que d'autres aussi, ne parlent pas couramment C.
flawr
Je ne suis pas d'accord avec l'argument d'unicité. Puisque la séquence de Fibonacci commence par 1, 1, 2, vous pouvez clairement décomposer 3 en F0 + F2 = 1 + 2 = 3. F0 et F2 ne sont pas adjacents.
orlp
1
@orlp La séquence de Fibonacci définie ici commence par F1 = 1 et F2 = 2. Donc, comme je le lis, F0 de votre définition ne fait pas partie de la séquence utilisée ici.
Reto Koradi

Réponses:

5

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

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

Essayez-le en ligne!

@ Algorithme de Bubbler

{ } fonction avec argument x

64( )/0 faire 64 fois, en utilisant 0 comme valeur initiale:

  • 1, ajouter 1

  • +': ajouter chaque préalable (laisser le premier élément intact)

F:attribuer à Fpour "séquence fibonacci"

| inverser

(.. ){y!x}\.. en commençant par la valeur de gauche, calculez les restes cumulés (de gauche à droite) pour la liste de droite. la valeur de gauche est la somme simple des entrées sans représentation zeckendorf:

  • 2\xcoder en binaire les entrées. ce sera une matrice nbits par 2

  • | inverser

  • +/' somme chacun

  • &où sont les 1? - liste des indices. s'il y a des 2, l'index correspondant est répété deux fois.

  • F@ indexation de tableau dans F

  • +/ somme

<': moins que chaque précédent (le premier du résultat sera toujours falsey)

2/ décodage binaire

ngn
la source
10

CJam, 76 74 70 63 59 octets

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

Essayez-le en ligne dans l' interpréteur CJam ou vérifiez tous les cas de test à la fois .

Idée

Nous commençons par définir une variation mineure de la séquence dans la question:

G -2 = 0
G -1 = 1
G k = G k-1 + G k-2 chaque fois que k est un entier non négatif

De cette façon, le bit 0 (LSB) de l'entrée ou de la sortie des tableaux de bits correspond au nombre de Fibonacci G 0 et, en général, du bit k à G k .

Maintenant, nous remplaçons chaque bit défini dans Z (n) et Z (m) par l'index qu'il code.

Par exemple, l'entrée 532 10 = 1000010100 2 est transformée en [2 4 9] .

Cela donne deux tableaux d'entiers, que nous pouvons concaténer pour en former un seul.

Par exemple, si n = m = 100 , le résultat est A: = [2 4 9 2 4 9] .

Si nous remplaçons chaque k dans A par G k et ajoutons les résultats, nous obtenons n + m = 200 , donc A est un moyen de décomposer 200 en nombres de Fibonacci, mais certainement pas celui du théorème de Zeckendorf.

En gardant à l'esprit que G k + G k + 1 = G k + 2 et G k + G k = G k + G k-1 + G k-2 = G k + 1 + G k-2 , nous pouvons substituer consécutifs et les index dupliqués par d'autres (à savoir, (k, k + 1) par k + 2 et (k, k) par (k + 1, k - 2) ), répétant ces substitutions encore et encore jusqu'à ce que la représentation de Zeckendorf soit atteinte. 1

Un cas particulier doit être pris pour les indices négatifs résultants. Puisque G -2 = 0 , l'indice -2 peut simplement être ignoré. De plus, G -1 = 0 = G 0 , donc tout -1 résultant doit être remplacé par 0 .

Pour notre exemple A , nous obtenons les représentations suivantes (triées), la dernière étant la représentation de 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]

Enfin, nous convertissons le tableau de nombres entiers en tableau de bits.

Code

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'implémentation tente de remplacer 32 fois et ne vérifie pas si la représentation de Zeckendorf a bien été atteinte. Je n'ai pas de preuve formelle que cela soit suffisant, mais j'ai testé toutes les sommes possibles de représentations 15 bits (dont les représentations de sommes nécessitent jusqu'à 17 bits) et 6 répétitions suffisaient pour toutes. Dans tous les cas, augmenter le nombre de répétitions à 99 est possible sans augmenter le nombre d'octets, mais cela réduirait les performances.

Dennis
la source
10

APL (Dyalog Extended) , 39 octets

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

Essayez-le en ligne!

Changé en un programme complet prenant un argument de longueur 2, et a également changé le générateur de Fibonacci. Merci à @ngn pour beaucoup d'idées.

Utilise ⎕IO←0pour que ⍳2s'évalue 0 1.

Générateur Fibonacci (nouveau)

Notez que les deux derniers chiffres sont inexacts, mais cela ne change pas la sortie du programme.

(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 à plaine (partiel)

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

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

Essayez-le en ligne!

Modification de la partie 1 de la réponse précédente pour réutiliser les numéros de Fibonacci. Supprimez également le doublon 1 pour enregistrer des octets à d'autres endroits.

Partie 1 (nouvelle)

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

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

Essayez-le en ligne!

Comment ça fonctionne

Aucun algorithme sophistiqué pour effectuer un ajout dans Zeckendorf car APL n'est pas connu pour fonctionner sur des éléments individuels dans un tableau. Au lieu de cela, j'ai continué à convertir les deux entrées de Zeckendorf en entiers simples, à les ajouter et à les reconvertir.

Partie 1: Zeckendorf en entier simple

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

Partie 2: ajouter deux entiers simples

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

Partie 3: Convertir la somme en Zeckendorf

"Vous pouvez supposer que les représentations Zeckendorf de l'entrée et de la sortie correspondent à 31 bits" était assez pratique.

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

Le générateur de 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

Cela découle de la propriété des nombres de Fibonacci: si Fibonacci est défini comme

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

puis

n0,je=0nFje=Fn+2-1

1,F0,,FnF1,,Fn+2

Chiffres de Fibonacci à 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.
Bubbler
la source
6

Haskell, 325 396 octets

EDIT: nouvelle version:

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 Fait le travail.

Leif Willerts
la source
Certaines choses peuvent être raccourcies immédiatement - par exemple, la fonction a la priorité la plus élevée, vous pouvez donc vous débarrasser des parents autour des applications de fonction, et les gardes n'ont pas non plus besoin de parents - les gardes s'arrêtent là où =c'est, donc les parents n'y sont pas nécessaires , et ainsi de suite et ainsi de suite, et notez que les :associés à droite et vous pouvez en couper là-bas. Mais bon, bravo! Semble très compliqué. J'ai hâte de comprendre comment cela fonctionne!
fier haskeller
@proudhaskeller Inutilement compliqué, cependant, voir mon montage. Dois-je expliquer l'idée de base? Cela pourrait être mieux d'une autre manière, mais j'ai essayé de faire autant de correspondance de motifs que possible au début. Ah, par parents, vous voulez dire entre parenthèses: ça a joué au golf!
Leif Willerts
chillax, c'est une de tes premières fois ici. Si vous restez longtemps, vous grandirez beaucoup mieux. Assurez-vous de vérifier la question des conseils de golf de Haskell pour un aperçu du codegolf.stackexchange.com/questions/19255/…
fier haskeller
@proudhaskeller edit est arrivé ...
Leif Willerts
4

ES6, 130 octets

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

À l'origine, j'ai essayé de calculer la somme en place (dans la ligne de l'implémentation de CJam), mais je continuais à manquer de temporels, donc je viens de convertir les nombres en et à partir d'entiers réels.

(Oui, je peux probablement enregistrer un octet en utilisant eval.)

Neil
la source
1

Rubis , 85 73 65 octets

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

Essayez-le en ligne!

Comment?

Obtenez d'abord une limite supérieure pour la somme codée: (a + b) * 2 est ok.

Maintenant, filtrez tous les numéros non zeckendorf de (0..limit).

Nous avons une table de recherche, c'est en descente d'ici.

GB
la source
1

Python 3, 207 octets

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

Essayez-le en ligne! (Vérifiez tous les cas de test)

Explication

Ce programme manipule directement les traductions binaires des représentations de Zeckendorf. La fonction a(n,m)effectue les calculs principaux et s(n)est une fonction d'aide qui supprime les nombres adjacents contenus dans la représentation de Zeckendorf.

Commençons par la fonction s(n)(développée pour plus de clarté):

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)

Par exemple, le nombre 107 ( 1101011en binaire, représentant 1 + 2 + 5 + 13 + 21 = 42), subit le processus suivant:

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)

Essayez-le en ligne! (s avec sortie détaillée)

Voici une version étendue de 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)

Cette fonction convertit les deux représentations de Zeckendorf en quatre nombres binaires plus faciles à combiner. La ligne (A) est le OU binaire des deux représentations binaires de Zeckendorf - celles-ci correspondent à une copie de chaque nombre de Fibonacci dans l'un ou l'autre groupe. (B) et (C) sont les ET binaires des deux nombres décalés à droite 1 et 2 fois, respectivement. Nous savons que lorsque les nombres de Fibonacci correspondants pour (B) et (C) sont additionnés, ils seront équivalents au ET binaire de notre net mparce que F (n) = F (n-1) + F (n-2) .

Par exemple, disons que nous avons les nombres binaires n = 101001 (correspondant à 1 + 5 + 13) et m = 110110 (2 + 3 + 8 + 13). Ensuite, nous aurons (A) = 111111 (1 + 2 + 3 + 5 + 8 + 13), qui est converti en 1010100 (3 + 8 + 21) par notre fonction s, (B) = 10000 (8), et ( C) = 1000 (5). Nous pouvons vérifier que (1 + 5 + 13) + (2 + 3 + 8 + 13) = (3 + 8 + 21) + (8) + (5) = 45. Ce processus se répète avec ((3 + 8 + 21) + (8)) + (5) = ((3 + 8 + 21) + (5) + (3)) + (5), etc.

La seule difficulté avec ce système est qu'il ne fonctionne pas pour les numéros de Fibonacci 1 et 2, car ils n'obéissent pas à la propriété F(n)=F(n-1)+F(n-2)(ce sont les deux nombres les plus bas)! De ce fait, à chaque fois 1 ou 2 est contenu à la fois net m, ils sont retirés de A, B et C, alors leur somme placée dans D sous la propriété que 1 + 1 = 2 et 2 + 2 = 1 + 3. Par exemple, si nous ajoutons 1 + 3 (101) + 1 + 3 + 5 (1101), nous obtenons:

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

(B): 2 (10)

(C): 1 (1)

(D): 2 (10)

Notez que les 3 et 5 ont été placés dans A, le 3 en double a été divisé en 2 + 1 en B et C, et les 1 en double ont été supprimés de A, B et C, ajoutés ensemble et mis en D.De même, si nous ajouter 2 + 3 (110) + 2 + 3 + 5 (1110), on obtient:

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

(B): 2 (10)

(C): 1 (1)

(D): 1 + 3 (101)

Essayez-le en ligne! (a avec sortie détaillée)

Madison Silver
la source
0

Wolfram Language (Mathematica) , 218 octets

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

Essayez-le en ligne!

Simplement l'appariement des motifs.

Non golfé:

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
la source