Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лаб3_рекурсия_студ.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
57.85 Кб
Скачать

1 Вариант

type

st = (left, middle, right);

nat = 1..maxint;

var

m: nat; {m – число дисков}

procedure move(n: nat; s1, sw, sk: st);

{перемещение n дисков с s1 на sk}

procedure step;

{перемещение одного диска с s1 на sk}

procedure print(s: st);

begin

case s of

left: write(' лев. ');

middle: write(' средн. ');

right: write(' прав. ')

end;

end;

begin {step}

write(' снять диск с ');

print(s1);

write(' надеть на ');

print(sk);

writeln

end;

begin {move}

if n = 1 then

step

else begin

move(n - 1, s1, sk, sw);

step;

move(n-1, sw, s1, sk)

end

end;

begin

writeln('введите число дисков')

read(m); {число дисков}

writeln('для ', m:3, ' дисков следует произвести ',

'следующие действия:');

move(m, left, middle, right);

end.

2 Вариант

Procedure Towers(n:byte; A, C, B : char)

{переложить N колец с А на С, используя В как промежуточный}

begin

if n=1 then writeln(A, ‘ ® ’, C)

else begin

Towers(n-1, A, B, C);

writeln(A, ‘ ® ‘, C);

Towers(n-1, B, C, A)

end

end;

begin

Towers(4, ‘A’, ‘C’, ‘B’) { решаем задачу при N = 4 }

end.

Пример 13. Задача о "восьми ферзях" — хорошо известный пример использования метода проб и ошибок и алгоритмов с возвратом. Этой задачей в 1780 г. занимался К. Ф. Гаусс, но полного ее решения не дал, и это не удивительно. Для подобного класса задач характерно отсутствие аналитического решения, но они требуют большого объема изнурительных вычислений, терпения, аккуратности. Поэтому такие задачи отдают для решения вычислительным машинам, обладающим вышеперечисленными достоинствами в полной мере.

Задача о восьми ферзях формулируется так: нужно расставить восемь ферзей на шахматной доске размером 8×8 таким образом, чтобы ни один ферзь не угрожал другому, то есть чтобы ни один из них не находился на одной и той же горизонтали, вертикали или диагонали, что и любой другой.

Грубый вариант решения задачи:

PROCEDURE Try(i: INTEGER);

BEGIN

инициация выбора положения i-гo ферзя;

REPEAT выбор очередного положения;

IF безопасно THEN поставить ферзя;

IF i < 8 THEN Try(i+1);

IF неудача THEN убрать ферзя END

END

END

UNTIL удача OR мест больше нет

END Try;

Чтобы идти дальше, нужно остановиться на каком-либо представлении для данных. Поскольку из шахматных правил мы знаем, что ферзь бьет все фигуры, находящиеся на той же самой вертикали, горизонтали или диагонали, то заключаем, что на каждой вертикали может находиться один и только один ферзь, поэтому при поиске места для i-го ферзя можно ограничить себя лишь i-й вертикалью. Таким образом, параметр i становится индексом вертикали, а процесс выбора возможного местоположения ограничивается восемью допустимыми значениями для индекса горизонтали j.

Остается решить вопрос: как представлять на доске эти восемь ферзей? Очевидно, доску вновь можно было бы представить в виде квадратной матрицы, но после небольших размышлений мы обнаруживаем, что это значительно усложнило бы проверку безопасности поля. Конечно, подобное решение нежелательно, поскольку такая операция выполняется очень часто. Поэтому хотелось бы остановиться на таком представлении данных, которое, насколько это возможно, упростило бы проверку. В этой ситуации лучше всего делать непосредственно доступной именно ту информацию, которая действительно важна и чаще всего используется. В нашем случае это не поля, занятые ферзями, а сведения о том, находится ли уже ферзь на данной горизонтали или диагонали. (Мы уже знаем, что на каждой k-й вертикали (1 <= k <= i) стоит только один ферзь.) Эти соображения приводят к таким описаниям переменных:

VAR x: ARRAY [1..8] OF INTEGER;

a: ARRAY [1..8] OF BOOLEAN;

b: ARRAY [b1..b2] OF BOOLEAN;

c: ARRAY [c1..c2] OF BOOLEAN;

где

xi обозначает местоположение ферзя на i-й вертикали;

aj указывает, что на j-й горизонтали ферзя нет;

bk указывает, что на k-й /-диагонали ферзя нет;

сk указывает, что на k-й \-диагонали ферзя нет.

Выбор границ индексов b1, b2, с1, с2 определяется исходя из способа вычисления индексов для b и с. На /-диагонали у всех полей постоянна сумма координат i и j, а на \-диагонали постоянна их разность. Оператор поставить ферзя превращается в такие операторы:

х[i] := j; a[j] := FALSE; b[i+j] := FALSE; c[i-j] := FALSE;

а оператор убрать ферзя — в такие:

a[j] := TRUE; b[i+j] := TRUE; c[i-j] := TRUE;

Условие безопасно выполняется, если поле с координатами i, j лежит на горизонтали и вертикали, которые еще не заняты. Следовательно, ему соответствует логическое выражение

а[j] & b[i+j] & c[i-j];

program ferz;

uses crt;

var s,i:integer;

a:array[1..8] of boolean;

b:array[2..16] of boolean;

c:array[-7..7] of boolean;

x:array[1..8]of integer;

procedure print;

var k:integer;

begin

s:=s+1;

write('Решение номер ',s:2,' : ');

for k:=1 to 8 do write(x[k]:4);

writeln;

write('Press <Enter>');

readln;

end;{of print}

procedure tr (i:integer);

var j:integer;

begin

for j:=1 to 8 do

if a[j]and b[i+j]and c[i-j] then

begin

x[i]:=j;

a[j]:=false;b[i+j]:=false;c[i-j]:=false;

if i<8 then tr(i+1) else print;

a[j]:=true;b[i+j]:=true;c[i-j]:=true;

end;

end;{of try}

begin{of main}

clrscr;

for i:=1 to 8 do a[i]:=true;

for i:=2 to 16 do b[i]:=true;

for i:=-7 to 7 do c[i]:=true;

s:=0;

tr(1)

end.