类斐波那契数列中的最低初始数


22

给定一个正整数输入N,输出两个非负数ab,其中a <b,具有尽可能低的平均值,这将导致数字N成为重复关系序列的一部分:

f(0) = a
f(1) = b
f(n) = f(n-2)+f(n-1)

如果存在多个解决方案,且ab的均值最小,则应输出具有最低b的解决方案

您可以假设N在您的语言/系统中代表的整数范围内。

测试用例

N = 1
a = 0, b = 1

N = 15
a = 0, b = 3

N = 21
a = 0, b = 1

N = 27
a = 0, b = 9   <- Tricky test case. [3, 7] is not optimal and [4, 3] is not valid

N = 100
a = 4, b = 10

N = 101
a = 1, b = 12

N = 102
a = 0, b = 3

N = 1000
a = 2, b = 10

如果a>=0并且a<b曾经有多种解决方案?
乔纳森·艾伦

我不能保证有或没有多个解决方案。两者1,42,3都会给出5,并且它们具有相同的均值。我猜有可能找到与那个相似的案例,这些是最低的平均值。如果您可以证明/证明没有多个解决方案,则无需检查该条件。
Stewie Griffin


3
可能的最低均值对应的OEIS序列A249783具有一张狂野的图
彼得·卡吉

1
@ØrjanJohansen我在答案中添加了一个证明,即没有重复的解决方案(因为我的答案取决于它)。
cardboard_box

Answers:


8

外壳19 18 16 14 13 15字节

感谢Zgarb保存1个字节。

ḟö£⁰ƒẊ++ÖΣṖ2Θḣ⁰

在线尝试!

说明:

免责声明:我真的不理解ȯƒẊ++代码部分。

编辑:它似乎翻译成Haskell fix.(mapad2(+).).(++),在这里mapad2对列表中的所有相邻对应用了apply函数。(尽管了解赫斯基,但在此程序的上下文中可能意味着其他含义)

            Θḣ⁰    Create the list [0..input]
          Ṗ2       Generate all possible sublists of length 2
        ÖΣ         Sort them on their sums
ḟ                  Find the first element that satisfies the following predicate.
    ƒẊ++             Given [a,b], magically generate the infinite Fibonacci-like
                     sequence from [a,b] without [a,b] at the start.
 ö£⁰                 Is the input in that list (given that it is in sorted order)?


我确定我已经尝试过...
H.PWiz

8

JavaScript(Node.js)92 90 89 91 83 82字节

-3个字节 -1个字节,感谢ThePirateBay

-8 -9字节归功于尼尔。

f=(n,a=1,b=0,c=(a,b)=>b<n?c(a+b,a):b>n)=>c(a,b)?b+2<a?f(n,a-1,b+1):f(n,b-~a):[b,a]

在线尝试!

注意:此解决方案依赖于一个事实,即永远不会有多个最小解决方案。

证明永远不会有多种解决方案:

FIB(a,b,k)以Fibonacci开头的序列a,b

FIB(a,b,0) = a
FIB(a,b,1) = b
FIB(a,b,k) = FIB(a,b,k-1) + FIB(a,b,k-2)

引理1

类斐波那契序列之间的差异本身就是类斐波那契,即FIB(a1,b1,k) - FIB(a0,b0,k) = FIB(a1-a0,b1-b0,k)。证明留给读者。

引理2

对于n >= 5a,b存在满足的解a+b < n以下条件:

如果n是偶数FIB(0,n/2,3) = n

如果n很奇怪FIB(1,(n-1)/2,3) = n

证明

情况下,n < 5可以彻底地检查。

假设我们有两个最小的解决方案n >= 5a0,b0a1,b1a0 + b0 = a1 + b1a0 != a1

然后存在k0,k1这样的FIB(a0,b0,k0) = FIB(a1,b1,k1) = n

  • 情况1: k0 = k1

    WLOG假设b0 < b1(因此a0 > a1

    DIFF(k)是之间的差异Fibonnaci般的开始序列a1,b1a0,b0

    DIFF(k) = FIB(a1,b1,k) - FIB(a0,b0,k) = FIB(a1-a0,b1-b0,k) (引理1)

    DIFF(0) = a1 - a0 < 0

    DIFF(1) = b1 - b0 > 0

    DIFF(2) = (a1+b1) - (a0+b0) = 0

    DIFF(3) = DIFF(1) + DIFF(2) = DIFF(1) > 0

    DIFF(4) = DIFF(2) + DIFF(3) = DIFF(3) > 0

    一旦像Fibonnaci的序列具有2个正项,则所有后续项均为正。

    因此,唯一的时间DIFF(k) = 0是何时k = 2,所以唯一的选择k0 = k12

    因此 n = FIB(a0,b0,2) = a0 + b0 = a1 + b1

    这些解决方案的最小性与引理2矛盾。

  • 情况2 k0 != k1::

    WLOG假设k0 < k1

    我们有 FIB(a1,b1,k1) = n

    a2 = FIB(a1,b1,k1-k0)

    b2 = FIB(a1,b1,k1-k0+1)

    然后FIB(a2,b2,k0) = FIB(a1,b1,k1) = FIB(a0,b0,k0)(为读者练习)

    由于对而言FIB(a1,b1,k)是非负的k >= 0,因此它也不在减少。

    这给了我们a2 >= b1 > a0b2 >= a1+b1 = a0+b0

    然后让DIFF(k) = FIB(a2,b2,k) - FIB(a0,b0,k) = FIB(a2-a0,b2-b0,k)(引理1)

    DIFF(0) = a2 - a0 > 0

    DIFF(1) = b2 - b0 >= (a0 + b0) - b0 = a0 >= 0

    DIFF(2) = DIFF(0) + DIFF(1) >= DIFF(0) > 0

    DIFF(3) = DIFF(1) + DIFF(2) >= DIFF(2) > 0

    再次DIFF具有2个正项,因此所有后续项均为正。

    因此,当它可能是唯一的一次DIFF(k) = 0k = 1,所以唯一的选择k01

    FIB(a0,b0,1) = n

    b0 = n

    这与引理2相矛盾。




@Neil最小化b而不是最小化a+b,因此您的解决方案给出了,f(27) = [3,7]但最佳解决方案是f(27)=[0,9]。还原重大更改后,我们减少到83个字节。
cardboard_box

1
我认为您可以使用b-~a代替保存另一个字节a+b+1
尼尔

1
您的第二种情况有一个小错误:a2 >= a1 + b1时不正确k1-k0=1。相反,您可以使用a2 >= b1 > a0b2 >= a1+b1 = a0+b0,然后其余的跟随。
与Orjan约翰森

8

Haskell76 72 74字节

编辑:

  • -4字节:@ H.PWiz建议使用/代替div,尽管这需要使用小数类型。
  • +2个字节:Enum通过添加,修复了带有范围的错误-1

f接受DoubleRational类型的值,并返回相同的元组。 Double应该足以满足所有不大到导致舍入误差的值,而Rational理论上是无限的。

f n|let a?b=b==n||b<n&&b?(a+b)=[(a,s-a)|s<-[1..],a<-[0..s/2-1],a?(s-a)]!!0

在线尝试!(H.PWiz的标题调整为输入/输出Rational整数格式的)

怎么运行的

  • ?是范围内的本地嵌套运算符fa?ba,b直到开始递归地执行类似Fibonacci的序列,直到精确命中时b>=n返回。Truen
  • 在列表理解中:
    • s通过从所有数值迭代1向上,代表的总和ab
    • a遍历从0到的数字s/2-1。(如果s为奇数,则范围的末尾四舍五入。)
    • a?(s-a)测试序列是否以a,s-ahits 开头n。如果是这样,则列表推导中将包含元组(a,s-a)。(即b=s-a,尽管它太短了,不值得命名。)
    • !!0 选择理解中的第一个元素(命中)。

8

APL(Dyalog)75 71 64 59 53 48 44 43字节

@Adám节省了2个字节

@ngn节省了12个字节

o/⍨k∊¨+\∘⌽⍣{k≤⊃⍺}¨oa/⍨</¨a←,⍉|-21+k←⎕

在线尝试!

用途 ⎕IO←0

怎么样? 这真是疯了。

k←⎕ -将输入分配给 k

⍳2⍴1+k←⎕-范围0k自身的

|-\¨ -从左侧减去每个右侧对元素,并获得绝对值

a←,⍉ -转置,展平并分配给 a

o←a/⍨</¨a -仅保留左侧元素小于右侧元素的对,并分配给 o

o现在包含的所有对的列表,a < b按其算术平均值排序

+\∘⌽⍣{k≤⊃⍺}¨o-对于中的每个对o,应用斐波那契(对和积反),直到k达到或达到更高的期限

k∊¨-然后确定这是否k是最后一项(意味着它包含在序列中)

o/⍨-并在o上一次检查适用的地方保持配对

-返回第一个结果。


5

Python 2中127 109 107字节

感谢ovs -2个字节(更改and*

g=lambda x,a,b:a<=b<x and g(x,b,a+b)or b==x
f=lambda n,s=1,a=0:g(n,a,s-a)*(a,s-a)or f(n,s+(a==s),a%s+(a<s))

在线尝试!

n,a,s-a什么奖励积分吗?

说明:

  • 第一行声明一个递归lambda,g它验证a, b斐波那契数列是否会达到扩展x。它还检查a <= b问题的条件之一。(这将允许a == b,但在这种情况下0, a已经发现并返回的情况)。
    • 链式不等式a<=b<x一次执行两项便捷的任务:验证a <= bb < x
    • 如果b < xyields True,则函数再次使用斐波那契数列中的下两个数字再次调用自身:b, a+b。这意味着该功能将继续制定新的条款,直到...
    • 如果b < x合格False,那么我们已经到达需要检查是否合格的地步了b==x。如果是这样,它将返回True,表示最初的配对a, b将最终到达x。否则,如果b > x,则该对无效。
  • 第二行声明另一个递归lambda,f它找到给定值的解决方案n。它递归地尝试新的初始对a, b,直到g(n, a, b)产生True。然后返回此解决方案。
    • 该函数使用两个变量s(初始为1)和a(初始为0)递归计算初始斐波那契对。在每次迭代中,a都会递增,并a, s-a用作第一对。但是,当a点击s,它将重置为0,并s递增。这意味着按以下方式对对进行计数:
      s = 1(0,1)(1,0)
      s = 2(0,2)(1,1)(2,0)
      s = 3(0,3)(1、2),(2、1),(3、0)
      
      显然,它包含一些无效对,但是当传递给时,这些对将立即消除g(请参阅第一个要点)。
    • 当值a,并s找到这样g(n, a, s-a) == True,那么这个值被返回。由于可能的解决方案是按照“大小”(按均值,然后是最小值)的顺序计算的,因此,第一个找到的解决方案将始终是最小的,这是挑战的要求。

3

R183字节 160字节

n=scan();e=expand.grid(n:0,n:0);e=e[e[,2]>e[,1],];r=e[mapply(h<-function(n,a,b,r=a+b)switch(sign(n-r)+2,F,T,h(n,b,r)),n,e[,1],e[,2]),];r[which.min(rowSums(r)),]

在线尝试!

感谢Giuseppe打高尔夫球23个字节

代码说明

n=scan()                        #STDIO input
e=expand.grid(n:0,n:0)          #full outer join of integer vector n to 0
e=e[e[,2]>e[,1],]               #filter so b > a
r=e[mapply(
  h<-function(n,a,b,r=a+b)switch(sign(n-r)+2,F,T,h(n,b,r)),
                                #create a named recursive function mid-call 
                                #(requires using <- vs = to denote local variable creation 
                                #rather than argument assignment
  n,e[,1],e[,2]),]              #map n, a and b to h() which returns a logical
                                #which is used to filter the possibilities
r[which.min(rowSums(r)),]       #calculate sum for each possibility, 
                                #get index of the minimum and return
                                #because each possibility has 2 values, the mean and 
                                #sum will sort identically.

1
160个字节 -通常,应尽可能保存字节,因此通过删除漂亮的命名来保存4个字节不仅是可以接受或鼓励的,而且在某种意义上是code-golf所要求的。即使这样,不错的答案还是+1。
朱塞佩

1

Mathematica,117个字节

If[#==1,{0,1},#&@@SortBy[(S=Select)[S[Range[0,s=#]~Tuples~2,Less@@#&],!FreeQ[LinearRecurrence[{1,1},#,s],s]&],Mean]]&


在线尝试!


1

果冻,19字节

ṫ-Sṭµ¡³e
0rŒcÇÐfSÐṂ

在线尝试!

-1字节感谢证明cardboard_box。如果被拒绝,您可以UṂṚ在第二行的末尾附加总共22个字节。


...领先的增长应该可以解决@StewieGriffin的观察。
乔纳森·艾伦

觉得您可以放弃
Jonathan Allan's

1
我们只需要查找使输入x,显示为最新的种子即可。如果x 多个第三索引处找到,那么它的工作原理为0,x,因此将在任也工作1,(x-1)/2x奇)或2,x/2-1x甚至),随后x将在后面的结果出现,这样不会发生。对于以后的碰撞,如果第三项也相同,则均值只能相同,但是初始项之间的差必须小(否则它们将是相同的),因此将x在以后的索引中找到。这样,我们可以ṫ-Sṭµ¡i³¶ḶŒcÇÐṀ节省四个字节。
乔纳森·艾伦

...糟糕,再加上增量:ṫ-Sṭµ¡i³¶‘ḶŒcÇÐṀ
乔纳森·艾伦

@StewieGriffin当我回答:p时,那个测试用例不存在:p
Outgolfer的Erik

1

GolfScript - 88 77字节

~:N[,{1+:a,{[.;a]}/}/][{[.~{.N<}{.@+}while\;N=]}/]{)1=\;},{(\;~+}$(\;);~~' '\

多亏了我的箱,我没有检查多种解决方案!

说明

~:N                           # Reads input
[,{1+:a,{[.;a]}/}/]           # Creates an array of pairs [a b]
[{[.~{.N<}{.@+}while\;N=]}/]  # Compute solutions
{)1=\;},         # Pairs that are not solutions are discarded
{(\;~+}$         # Sorts by mean
(\;);~~' '\      # Formats output


0

分批,160个 158字节

@set/aa=b=0
:g
@if %a% geq %b% set/ab-=~a,a=0
@set/ac=a,d=b
:l
@if %c% lss %1 set/ad+=c,c=d-c&goto l
@if %c% gtr %1 set/aa+=1,b-=1&goto g
@echo %a% %b%

这(也)给出3 7了input 27。正确的解决方案是0 9
cardboard_box

@cardboard_box仍然没有看到问题在哪里要求...
Neil

在第一句话中:“具有最低可能的平均值”。
cardboard_box

@cardboard_box啊,很抱歉,这太容易忽略了。
尼尔

1
@cardboard_box OK现在应该已修复。
尼尔
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.