Пролог; попробуйте сделать Фибоначчи более эффективным?
Это логическое программирование действительно делает танец на коленях на моих императивных навыках программирования. Это домашнее задание, так что, пожалуйста, не бросай мне ответ. Вот что у меня есть:--4-->
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 ответов
я мог бы опубликовать здесь решение, но так как это домашнее задание, оно было бы контрпродуктивным. Вместо этого, вот зацепка:
проблема с версией Фибоначчи, которую вы перечислили, заключается в том, что она неэффективна. Каждый вызов 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
чтобы преодолеть этот недостаток, вас попросили перефразировать Фибоначчи с точки зрения возврата не только последнего значения, но и последних двух значений, так что каждый вызов 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.
посмотреть связанные обсуждения:
обобщение последовательности Фибоначчи с помощью Sicstus Prolog
и рассмотрим очень хорошее решение ony, используя ограничения конечной области оттуда.
возможно, использование хвостовой рекурсии-хороший вариант
изменить: Вместо разбиения fib (6) на fib(5)+fib(4) Вы можете попробовать что-то вроде fib(6) = fib(6,0,0) первый параметр-это количество шагов, когда он достигает 0, вы останавливаетесь, второй параметр-последнее вычисленное вами значение, а третий параметр-это значение для вычисления, которое равно сумме текущих второго и третьего параметров (за исключением первого шага, в котором 0 + 0 будет 1)
Так чтобы вычислить, вы устанавливаете второй параметр при каждом вызове и acumulate в третьем so fib(6,0,0) => fib(5,0,1) => fib(4,1,1) => fib(3,1,2) => fib(2,2,3) => fib(1,3,5) => fib(0,5,8), затем вы возвращаете 8
в этом методе вам фактически не нужно сохранять в стеке возврат адреса, избегая переполнения стека
помните, что есть еще один способ вычисления последовательности Фибоначчи: начиная с базового случая и двигаясь вверх.
прямо сейчас, чтобы вычислить fib(n)
добавить fib(n-1)
и fib(n-2)
. Вместо этого переверните это и вычислите fib(0)
и fib(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):- ...
Я не понимаю, как я могу переписать это используя накопление
просто не надо, это не нужно (хотя это можно сделать).