Запишіть число як суму Фібоначчі


9

Давайте визначимо послідовність Фібоначчі як

F(1) = 1

F(2) = 2

F(n) = F(n - 2) + F(n - 1)

Отже, у нас є нескінченна послідовність 1,2,3,5,8,13,... Добре відомо, що будь-яке додатне ціле число може бути записане як сума деяких чисел Фібоначчі. Єдине застереження - це підсумок може бути не унікальним. Завжди існує принаймні один спосіб записати число у вигляді суми чисел Фібоначчі, але їх може бути набагато набагато більше.

Ваше завдання полягає в тому, щоб написати повну програму, яка за допомогою stdin приймає додатне ціле число від одного до одного мільйона включно, а потім виводить за допомогою stdout всі можливі підсумки чисел Фібоначчі, які підсумовують вхід. Підсумовуючи, числа Фібоначчі не повинні повторюватися, і це включає число 1. У будь-якому підсумку, якщо 1він присутній, він повинен бути присутнім лише один раз, тому що в моєму визначенні послідовність вище 1відображається лише один раз. Підсумки лише з терміном є дійсними, тому, якщо вхідним числом є саме число Фібоначчі, то саме число є дійсним підсумком і повинно бути надруковано. Якщо суми декілька, то між будь-якими двома сумами повинен бути порожній рядок, щоб їх легко розрізнити.

Ось кілька зразків.

./myfib 1
1

Є лише одна така сума, і вона має лише термін, так що це все, що друкується.

./myfib 2
2

Зауважте, що 1+1це неправдна сума, оскільки 1повторюється.

./myfib 3
1+2

3

Дві суми, і вони друкуються між собою порожнім рядком.

./myfib 10
2+8

2+3+5

./myfib 100
3+8+89

1+2+8+89

3+8+34+55

1+2+3+5+89

1+2+8+34+55

3+8+13+21+55

1+2+3+5+34+55

1+2+8+13+21+55

1+2+3+5+13+21+55

Справжній код-гольф. Виграє найкоротший код будь-якою мовою. Будь ласка, опублікуйте свій код із деякими тестовими кейсами (крім того, який я подав вище). Що стосується зв’язків, я вибираю той, хто має найвищі результати, після того, як чекаю принаймні два тижні і, мабуть, довше. Тож, громада, будь ласка, вітає будь-які рішення, які вам подобаються. Розумність / краса коду має значення набагато більше, ніж хто публікує першим.

Щасливого кодування!


1
... Я просто піду на цьому: P Якщо я опублікую відповідь, не сподівайтеся, що вона буде добре :)
Doorknob

Ну це код-гольф не найшвидший-код. :-D
Фіксована точка

1
Я написав це, і він насправді працює швидко: P
Дверна ручка

Не зовсім дублікат, але тісно пов'язаний з codegolf.stackexchange.com/q/2677/194
Пітер Тейлор

1
@shiona Оскільки я не вказав, виберіть улюблений. :-)
Фіксована точка

Відповіді:


9

GolfScript, 54 символи

~1.{3$)<}{.@+}/<[[]]{{+}+1$%+}@/\{~)+{+}*!}+,{'+'*n.}/

Перевірте його в Інтернеті або подивіться приклади:

> 54
2+5+13+34

> 55
1+2+5+13+34

3+5+13+34

8+13+34

21+34

55

4

Ruby, 118 114 (вихід масиву) або 138 134 (правильний вихід)

i=gets.to_i
a=[x=y=1]
a+=[y=x+x=y]until y>i
p (1..a.size).flat_map{|n|a.combination(n).select{|o|o.inject(:+)==i}}

Проба зразка:

c:\a\ruby>fibadd
100
[[3, 8, 89], [1, 2, 8, 89], [3, 8, 34, 55], [1, 2, 3, 5, 89], [1, 2, 8, 34, 55], [3, 8, 13, 21, 55], [1, 2, 3, 5, 34, 55], [1, 2, 8, 13, 21, 55], [1, 2, 3, 5, 13, 21, 55]]

Змініть getsна, $*[0]якщо ви хочете аргументи командного рядка ( >fibadd 100), хоча +1 символ.

При правильному виході:

i=gets.to_i
a=[x=y=1]
a+=[y=x+x=y]until y>i
$><<(1..a.size).flat_map{|n|a.combination(n).select{|o|o.inject(:+)==i}}.map{|o|o*?+}*'

'

Проби:

c:\a\ruby>fibadd
100
3+8+89

1+2+8+89

3+8+34+55

1+2+3+5+89

1+2+8+34+55

3+8+13+21+55

1+2+3+5+34+55

1+2+8+13+21+55

1+2+3+5+13+21+55
c:\a\ruby>fibadd
1000
13+987

5+8+987

13+377+610

2+3+8+987

5+8+377+610

13+144+233+610

2+3+8+377+610

5+8+144+233+610

13+55+89+233+610

2+3+8+144+233+610

5+8+55+89+233+610

13+21+34+89+233+610

2+3+8+55+89+233+610

5+8+21+34+89+233+610

2+3+8+21+34+89+233+610
c:\a\ruby>obfcaps
12804
2+5+21+233+1597+10946

2+5+8+13+233+1597+10946

2+5+21+89+144+1597+10946

2+5+21+233+610+987+10946

2+5+21+233+1597+4181+6765

2+5+8+13+89+144+1597+10946

2+5+8+13+233+610+987+10946

2+5+8+13+233+1597+4181+6765

2+5+21+34+55+144+1597+10946

2+5+21+89+144+610+987+10946

2+5+21+89+144+1597+4181+6765

2+5+21+233+610+987+4181+6765

2+5+8+13+34+55+144+1597+10946

2+5+8+13+89+144+610+987+10946

2+5+8+13+89+144+1597+4181+6765

2+5+8+13+233+610+987+4181+6765

2+5+21+34+55+144+610+987+10946

2+5+21+34+55+144+1597+4181+6765

2+5+21+89+144+233+377+987+10946

2+5+21+89+144+610+987+4181+6765

2+5+21+233+610+987+1597+2584+6765

2+5+8+13+34+55+144+610+987+10946

2+5+8+13+34+55+144+1597+4181+6765

2+5+8+13+89+144+233+377+987+10946

2+5+8+13+89+144+610+987+4181+6765

2+5+8+13+233+610+987+1597+2584+6765

2+5+21+34+55+144+233+377+987+10946

2+5+21+34+55+144+610+987+4181+6765

2+5+21+89+144+233+377+987+4181+6765

2+5+21+89+144+610+987+1597+2584+6765

2+5+8+13+34+55+144+233+377+987+10946

2+5+8+13+34+55+144+610+987+4181+6765

2+5+8+13+89+144+233+377+987+4181+6765

2+5+8+13+89+144+610+987+1597+2584+6765

2+5+21+34+55+144+233+377+987+4181+6765

2+5+21+34+55+144+610+987+1597+2584+6765

2+5+21+89+144+233+377+987+1597+2584+6765

2+5+8+13+34+55+144+233+377+987+4181+6765

2+5+8+13+34+55+144+610+987+1597+2584+6765

2+5+8+13+89+144+233+377+987+1597+2584+6765

2+5+21+34+55+144+233+377+987+1597+2584+6765

2+5+8+13+34+55+144+233+377+987+1597+2584+6765

Цей останній (12804) зайняв лише 3 секунди!


4

Математика, 89 85 символів

Скорочено до 85 годин завдяки Девіду Каррахеру.

i=Input[];#~Row~"+"&/@Select[If[#>i,Subsets@{##},#0[#+#2,##]]&[2,1],Tr@#==i&]//Column

Mathematica має вбудовану функцію Fibonacci, але я не хочу її використовувати.


Дуже компактний. Приємно.
Dr. belisarius

1
76 символів, якщо ви не заперечуєте надрукувати як перелік сум:i = Input[]; #~Row~"+" & /@ Select[If[# > i, Subsets@{##}, #0[# + #2, ##]] &[2, 1], Tr@# == i &]
DavidC

1
84 символів:i = Input[]; #~Row~"+" & /@ Select[If[# > i, Subsets@{##}, #0[# + #2, ##]] &[2, 1], Tr@# == i &] // Column
DavidC

2

Пітон 206 181 персонаж

import itertools as a
i,j,v,y=1,2,[],input()
while i<1000000:v,i,j=v+[i],j,i+j
for t in range(len(v)+1):
 for s in a.combinations(v,t):
  if sum(s)==y:print "+".join(map(str,s))+"\n"

Виконання зразка:

25
1+3+21

1+3+8+13

1000
13+987

5+8+987

13+377+610

2+3+8+987

5+8+377+610

13+144+233+610

2+3+8+377+610

5+8+144+233+610

13+55+89+233+610

2+3+8+144+233+610

5+8+55+89+233+610

13+21+34+89+233+610

2+3+8+55+89+233+610

5+8+21+34+89+233+610

2+3+8+21+34+89+233+610

Позбавтеся від усіх цих зайвих пробілів. Для вступу коду можна скористатися однією вкладкою або пробілами. Також запис циклів коду в одному рядку, коли можливо, коротше, тобтоwhile i<1000000:v+=[i];i,j=j,i+j
Васі

Деякі пропозиції (я не хочу просто плагіатом свою відповідь і відправити мою скорочену версію): import itertools as zвидаліть символ нового рядка після двокрапки, покласти y=input()в с x,y,vлінії, і видалити додатковий простір після остаточного ifзатвердження.
SimonT

Я включив ваші пропозиції до коду. Дякую :)
Бетмен

2

Скала, 171

def f(h:Int,n:Int):Stream[Int]=h#::f(n,h+n)
val x=readInt;(1 to x).flatMap(y=>f(1,2).takeWhile(_<=x).combinations(y).filter(_.sum==x)).foreach(z=>println(z.mkString("+")))

2

C #, 376 байт

class A{IEnumerable<int>B(int a,int b){yield return a+b;foreach(var c in B(b,a+b))yield return c;}void C(int n){foreach(var j in B(0,1).Take(n).Aggregate(new[]{Enumerable.Empty<int>()}.AsEnumerable(),(a,b)=>a.Concat(a.Select(x=>x.Concat(new[]b})))).Where(s=>s.Sum()==n))Console.WriteLine(string.Join("+",j));}static void Main(){new A().C(int.Parse(Console.ReadLine()));}}

Безголівки:

class A
{
    IEnumerable<int>B(int a,int b){yield return a+b;foreach(var c in B(b,a+b))yield return c;}
    void C(int n){foreach(var j in B(0,1).Take(n).Aggregate(new[]{Enumerable.Empty<int>()}.AsEnumerable(),(a,b)=>a.Concat(a.Select(x=>x.Concat(new[]{b})))).Where(s=>s.Sum()==n))Console.WriteLine(string.Join("+",j));}
    static void Main(){new A().C(int.Parse(Console.ReadLine()));}
}

Метод Bповертає an, IEnumerableякий представляє весь (нескінченний) набір Фібоначчі. Другий метод, заданий числом n, розглядає перші nчисла Фібоначчі (величезна надмірна кількість тут), знаходить усі можливі підмножини (набір потужності), а потім фільтрує до підмножини, сума якої точно n, а потім друкує.


1

APL (75)

I←⎕⋄{⎕←⎕TC[2],1↓,'+',⍪⍵}¨S/⍨I=+/¨S←/∘F¨↓⍉(N⍴2)⊤⍳2*N←⍴F←{⍵,+/¯2↑⍵}⍣{I<⊃⌽⍺}⍳2

Менш конкурентоспроможний, ніж я хотів би, в основному через формат виводу.

Вихід:

⎕:
      100

 3 + 8 + 89 

 3 + 8 + 34 + 55 

 3 + 8 + 13 + 21 + 55 

 1 + 2 + 8 + 89 

 1 + 2 + 8 + 34 + 55 

 1 + 2 + 8 + 13 + 21 + 55 

 1 + 2 + 3 + 5 + 89 

 1 + 2 + 3 + 5 + 34 + 55 

 1 + 2 + 3 + 5 + 13 + 21 + 55 

Пояснення:

  • I←⎕: читати вхід, зберігати в I.
  • ⍳2: починаючи зі списку 1 2,
  • {⍵,+/¯2↑⍵}: додайте до списку суму останніх двох елементів,
  • ⍣{I<⊃⌽⍺}: поки Iменший за останній елемент списку.
  • F←: зберігати в F(це цифри фішок від 1до I).
  • N←⍴F: збережіть кількість цифр у полі в N.
  • ↓⍉(N⍴2)⊤⍳2*N: отримати числа від 1до 2^N, як біти.
  • S←/∘F¨: використовуйте кожен із них як біт-маску F, зберігайте S.
  • I=+/¨S: для кожного підсписку в S, дивіться, чи сума його дорівнює I.
  • S/⍨: виберіть їх з S. (Зараз у нас є всі списки чисел, які дорівнюють I.)
  • {... : для кожного з них:
    • ,'+',⍪⍵: додайте +перед кожним номером,
    • 1↓: зняти перший +назад,
    • ⎕TC[2]: додайте додатковий новий рядок,
    • ⎕←: і вихід.

1

Хаскелл - 127

Після багатьох ітерацій я отримав такий код:

f=1:scanl(+)2f
main=getLine>>=putStr.a f "".read
a(f:g)s n|n==f=s++show f++"\n\n"|n<f=""|n>f=a g(s++show f++"+")(n-f)++a g s n

Я міг би врятувати, можливо, одного персонажа, обманувши і додавши додаткові "0+" перед кожним вихідним рядком.

Я хочу поділитися ще однією версією (довжина 143), яку я придумав, намагаючись переграти попереднє рішення. Я ніколи раніше так багато не зловживав операторами та кортежами:

f=1:scanl(+)2f
main=getLine>>=(\x->putStr$f€("",read x))
o%p=o++show p;(f:g)€t@(s,n)|n==f=s%f++"\n\n"|n<f=""|n>f=g€(s%f++"+",n-f)++g€t

Тестові приклади, 256:

256
2+3+5+13+34+55+144

2+3+5+13+89+144

2+3+5+13+233

2+8+13+34+55+144

2+8+13+89+144

2+8+13+233

2+21+34+55+144

2+21+89+144

2+21+233

і 1000:

1000
2+3+8+21+34+89+233+610

2+3+8+55+89+233+610

2+3+8+144+233+610

2+3+8+377+610

2+3+8+987

5+8+21+34+89+233+610

5+8+55+89+233+610

5+8+144+233+610

5+8+377+610

5+8+987

13+21+34+89+233+610

13+55+89+233+610

13+144+233+610

13+377+610

13+987

Деякі дані про ефективність, оскільки хтось мав цей матеріал:

% echo "12804" | time ./fibsum-golf > /dev/null
./fibsum-golf > /dev/null  0.09s user 0.00s system 96% cpu 0.100 total
% echo "128040" | time ./fibsum-golf > /dev/null
./fibsum-golf > /dev/null  2.60s user 0.01s system 99% cpu 2.609 total

0

05AB1E , 19 байт ( неконкурентоспроможний )

ÅFævy©O¹Qi®'+ý}})ê»

Спробуйте в Інтернеті!

Розраховує всі можливі суми за будь-яку дану n. Приклад виходу для 1000:

1+1+3+8+144+233+610
1+1+3+8+21+34+89+233+610
1+1+3+8+377+610
1+1+3+8+55+89+233+610
1+1+3+8+987
13+144+233+610
13+21+34+89+233+610
13+377+610
13+55+89+233+610
13+987
2+3+8+144+233+610
2+3+8+21+34+89+233+610
2+3+8+377+610
2+3+8+55+89+233+610
2+3+8+987
5+8+144+233+610
5+8+21+34+89+233+610
5+8+377+610
5+8+55+89+233+610
5+8+987
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.