ツェッケンドルフ表現の下での総和


14

ゼッケンドルフの定理は、すべての正の整数は隣接しないフィボナッチ数の合計として一意に表すことができることを示しています。この課題では、2つの数値の合計をツェッケンドルフ表現で計算する必要があります。


LET F NであるN番目のフィボナッチ数どこ

F 1 = 1、
F 2 = 2、および
すべてのk > 2の場合、F k = F k -1 + F k -2

非負の整数nツェッケンドルフ表現 Z(n)は、次のような正の整数のセットです。

NI ∈Z(N F I   及び
I ∈Z(N iは + 1つの∉Z(N)。

(プロサでは:数値nのゼッケンドルフ表現は、これらのインデックスのフィボナッチ数の合計がnになるような正の整数のセットであり、2つの隣接する整数がそのセットの一部ではありません)

特に、ツェッケンドルフの表現は独特です。ツェッケンドルフ表現の例をいくつか示します。

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 記述されたリファレンス実装はここにあります。また、Zeckendorf表現を生成したり、Zeckendorf表現から数値を計算したりするためにも使用できます。

以下は、入力と出力のサンプルのペアです。最初の2つの列には入力が含まれ、3番目の列には出力が含まれています。

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 2015

1
@orlpここで定義されているフィボナッチ数列は、F1 = 1およびF2 = 2で始まります。だから私がそれを読む方法、あなたの定義からのF0はここで使用されるシーケンスの一部ではありません。
Reto Koradi

回答:


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}\..左側の値から始めて、右側のリストの累積余り(左から右)を計算します。左側の値は、ツェッケンドルフ表現のない入力の単純合計です。

  • 2\x入力をバイナリエンコードします。これはnbits行2列の行列になります

  • |

  • +/' それぞれ合計

  • &1はどこですか?-インデックスのリスト。2がある場合、対応するインデックスが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フィボナッチ数のビット列の入力または出力対応の(LSB)G 0と、一般に、ビットKのG K

ここで、Z(n)およびZ(m)の各セットビットを、それがエンコードするインデックスに置き換えます。

たとえば、入力532 10 = 1000010100 2[2 4 9]に変換されます。

これにより、整数の2つの配列が生成されます。これを連結して、1つの配列を形成できます。

たとえば、n = m = 100の場合、結果はA:= [2 4 9 2 4 9]になります。

我々はそれぞれ交換した場合のkの中でAによってGのKおよび結果を追加、我々は入手N + M = 200、ようにAがある分解する方法200を確実ゼッケンドルフの定理から1ないフィボナッチ数に、しかし。

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))Zeckendorf表現が達成されるまで、何度もそれらの置換を繰り返します。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の引数を1つ取る完全なプログラムに変更され、フィボナッチジェネレーターも変更されました。たくさんのアイデアを@ngnに感謝します。

⎕IO←0がに⍳2評価されるように使用し0 1ます。

フィボナッチジェネレーター(新)

最後の2つの数値は不正確ですが、プログラムの出力は変更されません。

(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}⊥⊤)

オンラインでお試しください!

使い方

配列内の個々の要素の操作についてAPLが知られていないため、ツェッケンドルフで追加を行うための特別なアルゴリズムはありません。代わりに、2つの入力をZeckendorfからプレーン整数に変換し、それらを追加して、変換し直しました。

パート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: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Σ=0F=F+21

1F0FF1F+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

Haskell、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 仕事をします。


一部のものはすぐに短くなる可能性があります。たとえば、関数の優先順位が最も高いため、関数アプリケーションの周囲の親を取り除くことができ、ガードも親を必要としません-ガードはその場所に停止する=ため、親は必要ありません、等々、そして:右に仲間がいて、そこでカットできることに注意してください。しかし、とにかく、おめでとうございます!非常に複雑に見えます。これがどのように機能するかを理解するのが待ちきれません!
誇り高いハスケラー

@proudhaskellerしかし、むやみに複雑ですが、私の編集を参照してください。基本的な考え方を説明しましょうか。別の方法の方が良いかもしれませんが、最初はできるだけ多くのパターンマッチングを実行しようとしました。ああ、両親とは括弧を意味します。
Leif Willerts、2015

チラックス、ここは初めてです。あなたが長く滞在するなら、あなたははるかに良く成長します。いくつかの洞察力のための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

Ruby85 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

オンラインでお試しください!(すべてのテストケースを確認してください)

説明

このプログラムは、Zeckendorf表現のバイナリ変換を直接操作します。この関数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(11010112進数で、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)

この関数は、2つのZeckendorf表現を、結合しやすい4つの2進数に変換します。行(A)は、2つのバイナリゼッケンドルフ表現のビット単位のORです。これらは、いずれかのグループの各フィボナッチ数の1つのコピーに対応しています。(B)と(C)は、2つの数値をそれぞれ1と2回右シフトしたビット単位のANDです。(B)と(C)に対応するフィボナッチ数列を加算するnm、F(n)= F(n-1)+ F(n-2)であるため、 。

たとえば、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つの問題は、フィボナッチ数1と2に対しては機能しないことF(n)=F(n-1)+F(n-2)です。これは、それらがプロパティに従わないためです(それらは最小の2つの数です)。そのため、両方に1または2が含まれている場合、nおよびm、それらは、次いで、それらの和がプロパティ下Dに配置され、A、B、及びCから除去される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に配置され、複製3がBとCで2 + 1に分割され、複製1がA、B、Cから削除され、一緒に追加され、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] &
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.