Zeckendorf表示下的求和


14

Zeckendorf定理表明,每个正整数都可以唯一地表示为不相邻的斐波那契数之和。在此挑战中,您必须计算Zeckendorf表示形式中两个数字的和。


令F n为第n个斐波那契数,其中

F 1 = 1,
F 2 = 2,并且
对于所有k > 2,F k = F k -1 + F k -2

非负整数nZeckendorf表示 Z(n)是一组正整数,使得

Ñ ∈Z(Ñ ˚F   和
∈Z(Ñ + 1个∉Z(Ñ)。

(在prosa中:数字n的Zeckendorf表示是一组正整数,因此这些索引的斐波那契数之和为n,并且该集合中没有两个相邻的整数)

值得注意的是,Zeckendorf表示法是唯一的。以下是Zeckendorf表示形式的一些示例:

Z(0)=∅(空集)
Z(1)= {1}
Z(2)= {2}
Z(3)= {3}({1,2}不是3的Zeckendorf表示)
Z (10)= {5,2}
Z(100)= {3,5,10}

在此挑战中,Zeckendorf表示形式被编码为位集合,其中最低有效位表示if是否1是集合的一部分,等等。您可以假设输入和输出的Zeckendorf表示形式都适合31位。

你的任务是计算Z(ñ + )给出Z(ñ)和Z()。以八位位组为最短长度的解决方案获胜。

您可以在此处找到用ANSI C编写的参考实现。它也可以用于生成Zeckendorf表示形式或从其Zeckendorf表示形式计算数字。

以下是一些示例输入和输出对,其中前两列包含输入,第三列包含输出:

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请查看提供的参考实现。您可以使用它来生成自己的样本输入。
2015年

3
我会很高兴,如果你可以记录在这里,你想要什么,并提供一些例子,因为我,也许别人也一样,不谙C.
flawr

我不同意唯一性论点。由于斐波那契数列以1、1、2开头,因此您可以清楚地将3分解为F0 + F2 = 1 + 2 =3。F0和F2 相邻。
orlp

1
@orlp此处定义的斐波那契数列以F1 = 1和F2 = 2开头。因此,按照我的理解,您定义中的F0不属于此处使用的序列的一部分。
Reto Koradi 2015年

Answers:


5

K(ngn / k)45 43 42 41字节

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

在线尝试!

@Bubbler的算法

{ } 带参数的功能 x

64( )/0 使用0作为初始值执行64次:

  • 1, 前置1

  • +': 添加每个先验(保留第一个元素不变)

F:分配给F“斐波那契数列”

| 逆转

(.. ){y!x}\..从左边的值开始,为右边的列表计算累积的余数(从左到右)。左边的值是没有zeckendorf表示形式的输入的纯总和:

  • 2\x对输入进行二进制编码。这将是一个2位的nbits矩阵

  • | 逆转

  • +/' 每个加起来

  • &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解释器中在线尝试或一次验证所有测试用例

理念

我们首先定义问题序列的微小变化:

k为非负整数时,G -2 = 0
G -1 = 1
G k = G k-1 + G k-2

这样,输入或输出的位阵列的位0(LSB)对应于斐波那契数G 0,并且通常对应于位kG k

现在,我们将Z(n)Z(m)中的每个设置位替换为其编码的索引。

例如,输入532 10 = 1000010100 2转换为[2 4 9]

这将产生两个整数数组,我们可以将它们连接起来以形成一个整数。

例如,如果n = m = 100,则结果为A:= [2 4 9 2 4 9]

如果我们替换每个ķģ ķ和添加的结果,我们得到N + M = 200,所以一个分解的方式200到斐波那契数,但肯定不是从齐肯多夫定理的一个。

请记住,G k + G k + 1 = G k + 2G 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)),一遍又一遍地重复这些替换,直到达到Zeckendorf表示形式为止。1个

对于产生的负索引,必须采取特殊情况。由于G -2 = 0,索引-2可以简单地忽略。同样,G -1 = 0 = G 0,因此任何结果-1必须替换为0

对于示例A,我们获得以下(排序的)表示形式,最后一个是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]

最后,我们将整数数组转换回位数组。

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次,并且不检查是否实际上已达到Zeckendorf表示形式。我没有正式的证明,这已经足够了,但是我已经测试了15位表示形式的所有可能和(其和表示形式最多需要17位),并且6个重复就足够了。在任何情况下,都可以在不增加字节数的情况下将重复次数增加到99,但这会降低性能。


10

APL(Dyalog扩展),39字节

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

在线尝试!

更改为带有一个长度为2的参数的完整程序,还更改了Fibonacci生成器。感谢@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扩展),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扩展),52字节

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

在线尝试!

怎么运行的

Zeckendorf中没有花哨的算法可以做加法运算,因为APL在数组中单个元素上的运算尚不为人所知。相反,我继续将Zeckendorf的两个输入转换为纯整数,将它们相加,然后转换回去。

第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部分:将总和转换回Zeckendorf

“您可以假设输入和输出的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个;ñ0Fñ+2=Fñ+1个+Fñ

然后

ñ0一世=0ñF一世=Fñ+2-1个

所以累积总和 1个F0Fñ (以1开头的斐波那契数组)变为 F1个Fñ+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 做这份工作。


某些内容可能会立即缩短-例如,功能优先级最高,因此您可以在功能应用程序周围省掉父母,而且监护人也不需要父母-监护人停在原地=,因此不需要父母,依此类推,以此类推,请注意,:右侧有关联,您可以在此处剪切一些。但是,无论如何,恭喜!看起来非常复杂。迫不及待地想出这是如何工作的!
2015年

@proudhaskeller毫无用处的复杂,请看我的编辑。我可以解释一下基本思想吗?这可能是另一种更好的方法,但是我一开始尝试进行尽可能多的模式匹配。啊,父母的意思是括号:打高尔夫球!
Leif Willerts 2015年

chillax,这是您第一次来。如果停留时间长,您的成长会更好。一定要检查一些见解Haskell的高尔夫技巧问题codegolf.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可以。

现在从(0..limit)过滤掉所有非Zeckendorf数。

我们有一个查询表,从这里下坡。


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

在线尝试!(验证所有测试用例)

说明

该程序直接处理Zeckendorf表示形式的二进制翻译。该函数a(n,m)执行主要计算,并且s(n)是一个辅助函数,它消除了Zeckendorf表示形式中包含的相邻数字。

让我们从功能开始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)

此函数将两个Zeckendorf表示形式转换为四个易于组合的二进制数。行(A)是两个二进制Zeckendorf表示形式的按位或-它们对应于任一组中每个斐波那契数的一个副本。(B)和(C)分别是两个数字右移1和2的按位与。我们知道,当相应的斐波那契数为(B)和(C)被加在一起,它们将相当于位与我们的nm因为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)和( C)= 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被包含在两个nm,它们是从A,B,和C除去,然后它们的和放置在d属性下一个1 + 1 = 2和2 + 2 = 1 + 3。例如,如果我们加上1 + 3(101)+ 1 + 3 + 5(1101),则会得到:

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

(B):2(10)

(C):1(1)

(D):2(10)

请注意,将3和5放入A,在B和C中将重复的3拆分为2 + 1,并从A,B和C中删除重复的1,将它们加在一起,然后放入D。类似地,如果我们加2 + 3(110)+ 2 + 3 + 5(1110),我们得到:

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

(B):2(10)

(C):1(1)

(D):1 + 3(101)

在线尝试!(详细输出)


0

Wolfram语言(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] &
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.