写一个数字作为斐波那契总和


9

让我们将斐波那契数列定义为

F(1) = 1

F(2) = 2

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

因此,我们有无限的序列1,2,3,5,8,13,...众所周知,任何正整数都可以写成某些斐波纳契数的总和。唯一的警告是,这种求和可能不是唯一的。总有至少一种将数字写成斐波纳契数之和的方法,但可能还有更多的方法。

您的挑战是编写一个完整的程序,该程序使用stdin接受一个介于1到1百万之间的正整数,然后使用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因为我没有指定,所以选择您喜欢的一个。:-)
定点

Answers:


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(数组输出)或138134(正确输出)

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为,但+1个字符。$*[0]>fibadd 100

带有正确的输出:

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

Mathematica,89个 85个字符

多亏了David Carraher,缩短到了85个字符。

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

Mathematica具有内置功能Fibonacci,但我不想使用它。


非常紧凑。真好
belisarius博士2013年

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
Wasi 2013年

一些建议(我不想just窃您的答案并发布缩短的版本)import itertools as z:,在冒号后删除换行符,在行y=input()中插入x,y,v,并在最后if声明后删除多余的空格。
SimonT 2013年

我已经在代码中包含了您的建议。谢谢:)
蝙蝠侠2013年

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返回一个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:从获得的数字12^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
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.