序言;试着让斐波那契更有效?

时间:2010-11-23 00:04:10

标签: prolog fibonacci clpfd

这种逻辑编程实际上是在我的命令式编程技巧上跳舞。这是家庭作业,所以请不要给我答案。这就是我所拥有的:

fibo(N,1) :-
   N < 2,
   !. 
fibo(N,R) :-
   N1 is N-1,
   N2 is N-2,
   fibo(N1,R1),
   fibo(N2,R2),
   R is R1+R2.

我想要制作另一个看起来像这样的功能; fib(N,Value,LastValue)N是第n个数字,value是返回值。我不明白我怎么能用累积重写这个。而且由于它向后计数,我不知道它在计算任何东西之前如何“知道”最后一个值。 :s赞赏任何意见。

5 个答案:

答案 0 :(得分:5)

我可以在这里发布解决方案,但既然这是家庭作业,那就会适得其反。相反,这是一个领导:

您列出的Fibonacci版本存在的问题是效率低下。每次调用fibo/2都会导致另一个两个调用,但其中一些调用会计算相同斐波纳契数的值。例如,在伪代码中:

(a) fibo(4) -> fibo(3), fibo(2)
(b) fibo(3) -> fibo(2), fibo(1)
(c) fibo(2) -> fibo(1), fibo(0) % called from (a)
(d) fibo(2) -> fibo(1), fibo(0) % called from (b), redundant

为了克服这个缺陷,你被要求重新定义Fibonacci,不仅要返回最后一个值,还要返回最后两个值,这样每次调用fib/3都只会导致一次递归调用(因此计算)斐波纳契线性时间序列)。您需要将基本案例更改为:

fib(1,1,0).
fib(2,1,1).

我会把递归案件留给你。


对于不耐烦的

以下是递归案例:

fib(N, Val, Last) :-
  N > 2,
  N1 is N - 1,
  fib(N1, Last, Last1), % single call with two output arguments, 
                        % instead of two calls with one output argument
  Val is Last + Last1.

答案 1 :(得分:2)

参见相关讨论:

Generalizing Fibonacci sequence with SICStus Prolog

并考虑使用有限域约束的非常好的解决方案。

答案 2 :(得分:1)

也许使用尾递归是一个不错的选择

编辑: 你可以尝试像fib(6)= fib(6,0,0)这样的第一个参数就是步数,当它达到0时就停止了,而不是将fib(6)分解成fib(5)+ fib(4) ,第二个参数是你计算的最后一个值,第三个参数是要计算的值,它等于当前第二个和第三个参数的总和(第一步除外,其中0 + 0将为1)< / p>

所以计算你在每次调用时设置第二个参数并在第三个参数中累积,因此fib(6,0,0)=&gt; fib(5,0,1)=&gt; fib(4,1,1)=&gt; fib(3,1,2)=&gt; fib(2,2,3)=&gt; fib(1,3,5)=&gt; fib(0,5,8)然后你返回8

在该方法中,您实际上不必在堆栈中保存地址返回,从而避免堆栈溢出

答案 3 :(得分:0)

请记住,还有另一种计算斐波纳契数列的方法:从基础案例开始向上移动。

目前,要计算fib(n),您需要添加fib(n-1)fib(n-2)。相反,根据Fibonacci序列的定义翻转并计算fib(0)fib(1),并从中进行构建。

答案 4 :(得分:-1)

你几乎已经拥有它了。只需改写:

fibo(N, Value) :-
N1 is N-1, N2 is N-2,
 fibo(N1, LastValue),fibo(N2, SecondToLastValue),
 Value is LastValue + SecondToLastValue.

fibo2(N, Value, LastValue):- ...
  

我不明白我怎么能改写   这使用积累

请注意,不需要这样做(尽管可以这样做)。