Scrivi un numero come somma di Fibonacci


9

Definiamo la sequenza di Fibonacci come

F(1) = 1

F(2) = 2

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

Quindi abbiamo la sequenza infinita 1,2,3,5,8,13,... È noto che qualsiasi numero intero positivo può essere scritto come una somma di alcuni numeri di Fibonacci. L'unica avvertenza è che questa somma potrebbe non essere unica. C'è sempre almeno un modo per scrivere un numero come somma dei numeri di Fibonacci, ma potrebbero essercene molti di più.

La tua sfida è quella di scrivere un programma completo che usando stdin prenda un numero intero positivo compreso tra 1 e 1 milione incluso, e quindi emetta usando stdout tutte le possibili sommazioni dei numeri di Fibonacci che si sommano all'input. In una somma, i numeri di Fibonacci non devono ripetersi e questo include il numero 1. In ogni sommatoria, se 1presente, deve essere presente una sola volta perché nella mia definizione della sequenza sopra 1appare solo una volta. Le somme con solo termine sono valide, quindi se il numero di input è un numero di Fibonacci stesso, il numero stesso è una somma valida e deve essere stampato. Se più somme, quindi tra due somme deve esserci una riga vuota per distinguerle facilmente.

Ecco alcuni esempi.

./myfib 1
1

C'è solo una di queste somme e ha solo un termine, quindi è tutto ciò che viene stampato.

./myfib 2
2

Nota qui che 1+1non è una somma valida perché si 1ripete.

./myfib 3
1+2

3

Due somme e sono entrambe stampate con una linea vuota in mezzo.

./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

Vero code-golf. Vince il codice più corto in qualsiasi lingua. Pubblica il tuo codice con alcuni casi di test (oltre a quello che ho dato sopra). Nel caso di legami, scelgo quello con i voti più alti dopo aver atteso almeno due settimane e probabilmente più a lungo. Quindi la community non esita a votare qualsiasi soluzione ti piaccia. L'intelligenza / bellezza del codice conta molto più di chi pubblica per primo.

Buona programmazione!


1
... ho intenzione di rinforzare questo: P Se inserisco una risposta, non aspettarti che funzioni bene :)
Maniglia della porta

Beh, è ​​code-golf non il codice più veloce. :-D
Punto fisso

1
L'ho scritto e funziona davvero in fretta: P
Maniglia

Non proprio un duplicato, ma strettamente correlato a codegolf.stackexchange.com/q/2677/194
Peter Taylor

1
@shiona Dal momento che non ho specificato, scegli il tuo preferito. :-)
Punto fisso il

Risposte:


9

GolfScript, 54 caratteri

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

Provalo online o dai un'occhiata agli esempi:

> 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 (uscita array) o 138 134 (uscita corretta)

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

Esecuzione di esempio:

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

Cambia getsin $*[0]se vuoi argomenti da riga di comando ( >fibadd 100), +1 carattere però.

Con l'output corretto:

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*?+}*'

'

Esecuzioni campione:

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

Quest'ultimo (12804) ha impiegato solo circa 3 secondi!


4

Mathematica, 89 85 caratteri

Ridotto a 85 caratteri grazie a David Carraher.

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

Mathematica ha una funzione integrata Fibonacci, ma non voglio usarla.


Molto compatto. Bello.
Dr. belisarius,

1
76 caratteri se non ti dispiace stampare come un elenco di somme:i = Input[]; #~Row~"+" & /@ Select[If[# > i, Subsets@{##}, #0[# + #2, ##]] &[2, 1], Tr@# == i &]
DavidC

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

2

Pitone 206 181 caratteri

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"

Esempio di esecuzione:

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

Sbarazzati di tutti quegli spazi extra. Puoi usare una scheda o i caratteri spaziali per indentare il codice. Anche la scrittura dei codici di loop in una riga singola quando possibile è più breve, ovverowhile i<1000000:v+=[i];i,j=j,i+j
Wasi,

Alcuni suggerimenti (non volevo solo plagiare la tua risposta e pubblicare la mia versione abbreviata) import itertools as z:, rimuovere le nuove righe dopo i due punti, inserire l'interno y=input()con la x,y,vriga e rimuovere lo spazio extra dopo la ifdichiarazione finale .
SimonT,

Ho incluso i tuoi suggerimenti nel codice. Grazie :)
Batman,

2

Scala, 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 byte

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

Ungolfed:

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

Il metodo Brestituisce un valore IEnumerableche rappresenta l'intero (infinito) set di Fibonacci. Il secondo metodo, dato un numero n, esamina i primi nnumeri di Fibonacci (enorme overkill qui), trova tutti i possibili sottoinsiemi (il set di potenze), quindi filtra fino a sottoinsiemi la cui somma è esattamente n, quindi stampa.


1

APL (75)

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

Meno competitivo di quanto mi piacerebbe, soprattutto a causa del formato di output.

Produzione:

⎕:
      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 

Spiegazione:

  • I←⎕: lettura input, memorizzazione in I.
  • ⍳2: a partire dall'elenco 1 2,
  • {⍵,+/¯2↑⍵}: aggiungi la somma degli ultimi due elementi all'elenco,
  • ⍣{I<⊃⌽⍺}: until Iè più piccolo dell'ultimo elemento dell'elenco.
  • F←: store in F(questi sono i numeri di fibonacci da 1a I).
  • N←⍴F: memorizza la quantità di numeri di fibonacci in N.
  • ↓⍉(N⍴2)⊤⍳2*N: ottiene i numeri da 1a 2^N, come bit.
  • S←/∘F¨: usa ognuno di questi come maschera di bit F, archivia S.
  • I=+/¨S: per ciascun elenco secondario in S, vedere se la somma è uguale a I.
  • S/⍨: selezionali da S. (Ora abbiamo tutti gli elenchi dei numeri di fibonacci che sommano I.)
  • {... : per ognuno di questi:
    • ,'+',⍪⍵: aggiungi un +davanti a ciascun numero,
    • 1↓: togli il primo +indietro,
    • ⎕TC[2]: aggiungi una nuova riga in più,
    • ⎕←: e output.

1

Haskell - 127

Dopo molte iterazioni ho finito con il seguente codice:

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

Avrei potuto salvare forse un personaggio ingannando e aggiungendo un ulteriore "0+" davanti a ogni linea di output.

Voglio condividere un'altra versione (lunghezza 143) che mi è venuta in mente mentre cercavo di giocare a golf con la soluzione precedente. Non ho mai abusato di operatori e tuple così tanto prima:

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

Casi di test, 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

e 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

Alcuni dati sull'efficienza da quando qualcuno aveva queste cose:

% 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 byte (non concorrenti)

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

Provalo online!

Calcola tutte le possibili somme per ogni dato n. Esempio di output per 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
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.