- •Лекция 9. Рекурсия Введение
- •Рекурсивные описания алгоритмов.
- •Реализация рекурсии
- •Примеры рекурсивных и нерекурсивных описаний
- •Var I: Integer; y: Real;
- •Var X:Integer;
- •Var s: Sequence;
- •Var I: Integer;
- •Var j : integer; Buf: Char;
- •Var s : Sequence;
- •Var j : integer;
- •Техника рекурсивных описаний
- •Var I, j, y, z : Integer;
- •Var a, X : Vector; b : Integer; I : Integer;
- •Преимущества и недостатки рекурсивных алгоритмов
Техника рекурсивных описаний
Несколько примеров рекурсивных процедур, рассмотренных в этом пункте, помогут лучшему усвоению техники применения рекурсии. Мы также увидим преимущества и недостатки рекурсивных описаний.
Пример 7. Ханойские башни.
Классический пример применения рекурсии для описания эффективного алгоритма - задача о ханойских башнях.
Анализ и неформальное описание алгоритма. Пусть N - количество колец на стержне, I - номер кольца, с которого осуществляется перестановка и J - номер кольца, на которое кольца требуется переставить.
HanojTower( N, I, J) - процедура, переставляющая N колец с I-того стержня на J-тый.
Step(I, J) - процедура, переставляющая одно кольцо с I-того стержня на J-тый.
(Если I и J - номера 2-стержней, то 6-I-J - номер третьего стержня.)
Предположим, что мы переместили N-1 кольцо с I-того стержня на 6-I-J стержень. Тогда можно переместить кольцо со стержня I на J.
На стержне J лежит кольцо с наибольшим диаметром, т.е. этот стержень можно использовать без нарушения ограничений, связанных с величинами диаметров. Поэтому можно теперь переставить всю пирамиду из N-1 кольца со стержня 6-I-J на J, и задача решена!
При N = 1 задача решается за один шаг - процедурой Step(I, J). Тем самым установлен базис рекурсии. Опишем теперь процедуру HanojTower(N, I, J):
Procedure HanojTower(N, I, J: Integer);
Begin
If N = 1
then Step(I, J)
else begin
HanojTower(N-1, I, 6-I-J);
Step(I, J);
HanojTower(N-1, 6-I-J, J)
end
End;
Определим сложность алгоритма по времени T(n) в терминах количества шагов (вызовов Step), выписав рекуррентное соотношение:
T(n) = 2T(n-1) + 1
Легко показать, что
T(n) = 2n - 1.
Пример 8. Линейные диофантовы уравнения. Перечислить все неотрицательные целые решения линейного уравнения
a1x1 + a2x2 + ... + anxn = b
c целыми положительными коэффициентами.
Перепишем исходное уравнение в виде:
a1 x1 + a2 x 2 + ... + a n-1 x n-1 = b - a n x n
Организуем перебор всевозможных значений xn, при которых правая часть b-a n x n > 0. xn = 0, 1, ... y, где y = b div an. Тогда первые n-1 компонент решения (x1, ... , x n-1, x n) исходного уравнения - решение уравнения
a1 x1 + a2 x2 + ... + a n-1 x n-1 = b - a n x n .
Таким образом, мы свели решение исходного уравнения к решению y+1 уравнения с n-1 неизвестным, и, следовательно, можем реализовать алгоритм рекурсивно. Определим условия выхода из рекурсии:
при b = 0 существует единственное решение - (0, 0, ..., 0)
при n = 1 если b mod a1 = 0
то x1 = b div a1
иначе решений нет.
Таким образом, выходить из рекурсивных вычислений нужно в двух (крайних) случаях. Мы установили и параметры процедуры: n и b, базис рекурсии, шаг рекурсии и условия рекурсии.
Procedure Solution(n, b : integer);
Var I, j, y, z : Integer;
Begin
If b = 0
then begin
For j := 1 to n do X[j] := 0; WriteSolution
end
else If (n = 1) and (b mod a[1] = 0)
then begin
X[1]:= b div a[1]; WriteSolution
end
else If n > 1
then begin
z := a[n]; y := b div z;
For i := 0 to y do begin
X[n] := i; Solution(n - 1, b - z*i)
end
end
End;
Program AllSolutions;
Const n = 4;
Type Vector = array[1..n] of Integer;