Открыть Электронные книги
Категории
Открыть Аудиокниги
Категории
Открыть Журналы
Категории
Открыть Документы
Категории
1
Классическими задачами, на которых обычно демонстрируется этот подход,
являются обход конем доски размером N×N, расстановка N ферзей на доске N×N
и задача коммивояжера.
Решаемые методом перебора с возвратом задачи, как правило, принадлежат
одному из трех классов – требуется либо найти произвольное из решений, либо
перечислить все возможные решения, либо найти решение, оптимальное по
заданному критерию.
Пусть глобальная логическая переменная Success получает значение True
как только будет найдено решение. До начала работы алгоритма она должна быть
инициализирована в False. Пусть также i – переменная, характеризующая
глубину рекурсии и передаваемая как параметр рекурсивной процедуре.
Алгоритм перебора с возвратом для нахождения одного решения
procedure Back1(i:integer);
begin
формирование списка кандидатов
repeat
выбор очередного кандидата (перебор)
if подходит then
begin
запись кандидата
if решение неполное then
begin
Back1(i+1);
if not Success then
стирание кандидата (возврат)
end;
else Success:=True
end;
until Success or кандидатов больше нет
end;
2
Отметим, что как только переменная Success получает значение True, мы
выходим из всех рекурсивных вызовов процедуры Back1, не совершая никаких
дополнительных действий.
Требуется продолжать обход доски, если верно i<n2. По правилам хода коня
из клетки с координатами (x, y) можно сделать 8 ходов и получить текущее
положение с координатами (u, v).
4
function Back1(i,x,y: integer):boolean;
var k, // номер кандидата или число возможных вариантов ходов
коня
u,v: integer; // координаты следующего хода коня
Success: boolean; //результат обхода после выполнения
очередного шага
begin
k:=0; Success:=False;
repeat
k:=k+1; // номер варианта для хода коня
u:=x+dx[k];
v:=y+dy[k];//вычисление координат следующего хода коня
if (u>0) and (u<=n) and (v>0) and (v<=n)
then //в пределах доски
If Solution[u,v]=0
then //клетку не посещали или она свободна
begin
Solution[u,v]:=i;
if i<n*n then
//есть не пройденные клетки
begin//обход доски со следующей позиции коня
Success:= Back1(i+1,u,v);
if not Success then //возврат на
предыдущий шаг
Solution[u,v]:=0;//клетка объявляется
свободной
end
else
Success:=True//всю доску обошли
end
until Success or (k=8);
5
Back1:= Success;
end;
begin // основная программа
read(x0,y0);
Solution[x0,y0]:=1;
if Back1(2,x0,y0) then
for i:=1 to n do // вывод массива ходов
begin
for j:=1 to n do
Write(Solution[i,j],' ');
writeln
end
else writeln('net resenia');
end.
Если размер доски 5×5, а начало обхода осуществляется с клетки с
координатами (n,n), то в результате вызова функции Back1(2,5,5) будет
сформирована матрица, содержащая номера ходов коня.
6
procedure Backall(i: integer);
begin
Формирование списка кандидатов
repeat
выбор очередного кандидата
if подходит then
begin
запись кандидата
if решение неполное then
Backall(i+1)
else печать решения (или его обработка)
стирание кандидата
end
until кандидатов больше нет
end;
Решение:
7
var
{признак занятости диагоналей первого типа }
up: array[2 .. 16] of boolean;
8
up[i+j] := false;
down[i-j] := false;
end;
9
else begin
inc(s);
print;
end;
end;
Общая схема перебора всех возможных решений, где X1 , X2 , ... , Xn –
представляет собой пространство перебора.
procedure перебор_с_возвратом(i : integer);
var k : integer;
begin
if i > n then
<найдено решение - печать>
else
for k:=1 to nr[i] do begin
x[i]:= k;
if <x[i] совместимо с x[1],...,x[i-1]> then
перебор_с_возвратом(i+1);
end;
end;
10
Пусть лабиринт представлен матрицей L, состоящей из n строк и m колонок,
со значениями элементов 0 (проход) и 1 (стена/барьер). На позиции (xb,yb)
расположен кусок сыра, на позиции (xs,ys) – мышка. Необходимо вывести все
возможные достижимые перемещения мышки к сыру, зная, что она может
перемещаться только через свободные проходы в направлениях С, СВ, В, ЮВ, Ю,
ЮЗ, З, СЗ.
Например, для лабиринта 4×4 с позицией мыши (1,1) и сыра (4,4)
перемещения м.б.
0 1 1 1
0 1 1 1
0 1 0 0
1 0 1 0
Решение 1: Решение 2:
* 1 1 1 * 1 1 1
* 1 1 1 * 1 1 1
* 1 * * * 1 * 0
1 * 1 * 1 * 1 *
11
Чтобы не проверять постоянно, если мышка не дошла каким-то образом до
границы лабиринта, обнесем лабиринт стеной (соответственно две строки и
колонки определим значением 1).
Условия:
Из позиции (x,y) мышка может переместиться в направлении dir, т.е. на
позицию (x+Dx[dir],y+Dy[dir]), только если
L[x+Dx[dir],y+Dx[dir]]=0
(эта позиция является проходом, через который сможет пройти мышка).
program Labirint;
const
type
var L: Labirint;
k,NRes: word;
procedure Init;
var i, j: Index;
begin
readln(n,m);
12
for i:=1 to n do
for j:=1 to m do
read(L[i,j]) ;
end;
var i: Index;
begin
end;
begin
Final := false;
end;
procedure Vivod;
begin
inc(Nres);
13
writeln(Решение №', NRes);
for j:= 1 to m do
write(L[i,j]);
writeln
end;
end;
begin
if Final(x,y) then
Vivod
else
for dir:=1 to 8 do
end;
Init; Stena;
14
Poisk(xs,ys,1);
end.
15