Backtracking, INFORMATYKA - ROK 1, Algorytmy i struktury danych


Algorytmy z nawrotami

(backtracking)

Algorytmy z nawrotami poznamy na przykładzie dwóch problemów „szachowych”: rozstawienia hetmanów i wędrówki skoczka po szachownicy.

Rozstawienie hetmanów

Problem polega na rozstawieniu n hetmanów na szachownicy n*n w taki sposób, by się nawzajem nie atakowały. Przypomnijmy, że hetman atakuje każde pole znajdujące się bądź w tym samym wierszu co on, bądź w tej samej kolumnie, bądź na jednej z dwóch przekątnych (patrz rysunek poniżej).

0x08 graphic

Jak łatwo sprawdzić, dla n=2 i 3, rozwiązania nie istnieją. Dla większych wartości n rozwiązania istnieją, co więcej, dla dużych n jest ich bardzo dużo. Chcemy napisać program, który dla zadanego n będzie znajdować którekolwiek z tych rozwiązań.

0x08 graphic
0x08 graphic

0x08 graphic

Algorytm naiwny mógłby polegać na sprawdzaniu wszystkich możliwych ustawień hetmanów. Ze względu olbrzymią liczbę tych ustawień efektywność tego algorytmu jest co najmniej wątpliwa. Istnieję algorytmy znacznie bardziej efektywne. Bazują one na regularności rozwiązań. Przyglądając się Rysunkowi 2 łatwo zauważyć, że w obydwu przedstawionych rozwiązaniach hetmany ustawione są wzdłuż dwóch linii. Łatwo się przekonać (do czego zachęcam czytelnika), że rozwiązania te dają się rozszerzyć na wiele innych wartości n, w szcególności na n nieparzyste.

Algorytm z nawrotami, który rozważymy, jest dość prostą modyfikacją algorytmu naiwnego. Przedstawiamy go, by zilustrować klasyczną technikę programowania.

Idea algorytmu.

Algorytm próbuje ustawiać hetmany w kolejnych kolumnach począwszy od pierwszej kolumny (oczywiście w każdej kolumnie ustawia tylko jednego hetmana). W każdej z kolumn szuka pierwszego pola (począwszy od dolnego), na którym postawienie hetmana nie koliduje z hetmanami z wcześniejszych kolumn. Jeśli takie pole istnieje, ustawia na nim hetmana i przechodzi do kolejnej kolumny. Jeśli nie istnieje - algorytm powraca do poprzedniej kolumny i próbuje przestawić hetmana na kolejne nie kolidujące pole. Może się zdarzyć, że algorytm będze musiał cofnąć się aż do pierwszej kolumny. Taka sytuacja pokazana jest na Rysunku 3.

0x08 graphic
0x08 graphic

Implementacja

Sprawdzanie czy pole jest atakowane

Jednym z problemów, które będziemy musieli rozwiązać, jest znalezienie metody sprawdzania, czy dane pole (powiedzmy pole <i, j>) szachownicy nie jest atakowane przez hetmany ustawione we wcześniejszych kolumnach. W tym celu musimy sprawdzić, czy żaden z tych hetmanów nie znajduje się:

Jak łatwo zauważyć, pola dla których obydwa indeksy są sobie równe leżą na tej samej przekątnej, idącej od lewego górnego pola do prawego dolnego pola. Tuż nad nią leżą pola, których pierwszy indeks jest o jeden mniejszy od drugiego indeksu, a tuż pod nią - pola, których pierwszy indeks jest o jeden większy od drugiego indeksu. Te obserwacje skłaniają nas do uważniejszego przyjrzenia się róznicom i sumom indeksów pól. (patrz Rysunek 4).

0x08 graphic

Tak więc sprawdzenie, czy pole leży na tej samej przekątnej co pole <i,j>, sprowadza się porównania różnicy indeksów tego pola z wartością i-j oraz sumy jego indeksów z wartością i+j.

Pamiętanie rozstawienia hetmanów

Może się wydawać, że algorytm musi używać dwuwymiarowej tablicy [1..n,1..n] do pamiętania stanu wszyskich pól szachownicy. Zauważmy jednak, że wystarczy pamiętać pozycje hetmanów. Do tego celu użyjemy jednowymiarowej tablicy

w:array[1..n] of integer;

Element w[i] będzie równy j, jeśli w i-tej kolumnie hetman został ustawiony w j-tym wierszu. Przykładowo, dla rozstawienia hetmanów z Rysunku 3, tablica w przyjmie wartości:

0x08 graphic

0x08 graphic
0x08 graphic
0x08 graphic
Program

Komentarz do wybranych instrukcji:

for i:=1 to x-1 do.....

wówczas jednak nie moglibyśmy tak elegancko zakończyć pętli w przypadku, gdy już znajdziemy hetmana atakującego pole <x,y>. Do przerwania pętli for moglibyśmy użyć instrukcji break, jednak występuje ona nie we wszystkich wersjach Pascala.

repeat

inc(w[k])

until (w[k]>n) or wolne(k,w[k]);

Kolejne instrukcje inc przesuwają hetmana po kolejnych polach k-tej kolumny tak długo, aż napotkamy nie atakowane pole bądź wyskoczymy hetmanem poza szachownicę. To, z którą sytuacją mamy do czynienia badane jest w instrukcji

if (w[k]<=n) then inc(k)

else begin w[k]:=0; dec(k) end

Jeśli w[k]<=n, to hetmana w k-tej kolumnie udało się ustawić, a więc należy przejść do następnej kolumny (inc(k)); w przeciwnym razie musimy cofnąć się do poprzedniej kolumny (dec(k)), a wartość w[k] należy ustawić na 0, co odpowiada temu, że k-ty hetman jest poza szachownicą.

Wędrówka skoczka po szachownicy

program konik;

const n=8; m=8;

type pole=record x,y:integer end;

var ruchy: array[1..8] of pole;

lr,kier:integer;

pk:pole;

sz:array[1..n,1..m] of integer;

hist:array[0..m*n] of pole;

procedure init;

var i,j:integer;

begin

ruchy[1].x:=2 ; ruchy[1].y:=1 ;

ruchy[2].x:=1 ; ruchy[2].y:=2 ;

ruchy[3].x:=-1 ; ruchy[3].y:=2 ;

ruchy[4].x:=-2 ; ruchy[4].y:=1 ;

ruchy[5].x:=-2 ; ruchy[5].y:=-1;

ruchy[6].x:=-1 ; ruchy[6].y:=-2;

ruchy[7].x:=1 ; ruchy[7].y:=-2;

ruchy[8].x:=2 ; ruchy[8].y:=-1;

for i:=1 to n do

for j:=1 to m do sz[i][j]:=0;

pk.x:=1; pk.y:=1;

lr:=1;

hist[1].x:=1; hist[1].y:=1;

end;

procedure cofnij;

begin

sz[pk.x,pk.y]:=0;

dec(lr);

pk.x:=hist[lr].x; pk.y:=hist[lr].y;

end;

procedure przesun(nr:integer);

begin

sz[pk.x,pk.y]:=nr;

inc(lr);

pk.x:=pk.x+ruchy[nr].x; pk.y:=pk.y+ruchy[nr].y;

hist[lr].x:=pk.x; hist[lr].y:=pk.y

end;

function okreslonyruch(skad:pole; kier:integer):boolean;

var nx,ny:integer;

begin

nx:=skad.x+ruchy[kier].x;

ny:=skad.y+ruchy[kier].y;

okreslonyruch:=(nx>=1) and (nx<=n) and (ny>=1) and (ny<=m)

end;

function nastruch(skad:pole):integer;

var kier:integer;

begin

kier:=sz[skad.x,skad.y];

repeat

inc(kier)

until (kier>8) or okreslonyruch(skad,kier) and

(sz[skad.x+ruchy[kier].x,skad.y+ruchy[kier].y]=0);

if kier>8 then nastruch:=0 else nastruch:=kier

end;

procedure pokazwynik;

var i,j:integer;

begin

writeln;

for i:=1 to n*m do writeln(hist[i].x:3, hist[i].y:3)

end;

begin

init;

while (lr>=1) and (lr<m*n) do

begin

kier:=nastruch(pk);

if kier=0 then cofnij else przesun(kier)

end;

if lr=0 then writeln('nie mozna skoczkiem obejsc szachownicy ',n,' x ',m)

else pokazwynik

end.

H

Rys.1. Kółkiem oznaczone są pola atakowane przez hetmana znajdującego się na polu z literą H

Rys.2. Przykładowe rozwiązania dla n=4 i n=5.

H

H

H

H

H

H

H

H

H

H

H

H

Rys.3. W pewnym momencie działania algorytm zachłanny dochodzi do sytuacji przedstawionej obok. Próba znalezienia niekolidującego pola w czwartej kolumnie zakończy się niepowodzeniem. Podonie zakończą się proby przestawienia hetmanów w 3-ciej, a następnie w 2-giej kolumnie. Skuteczne okaże się dopiero przestawienie hetmana w pierwszej kolumnie o jeden wiersz do góry.

i=

1

2

3

4

5

6

7

8

j= 1 2 3 4 5 6 7 8

1 2 3 4 5 6 7 8

i-j= 7 6 5 4 3 2 1 0

i-j=

-7

-6

-5

-4

-3

-2

-1

i+j=

2

3

4

5

6

7

8

i+j= 9 10 11 12 13 14 15 16 0

Rys.4. Wszystkie pola leżące na tej samej przekątnej idącej z lewego górnego rogu do prawego dolnego rogu mają taką samą sumę indeksów (lewy rysunek). Natomiast pola leżące na tej samej przekątnej idącej z prawego górnego do lewego dolnego rogu maja taką samą różnicę indeksów (prawy rysunek).

1 4 2 0

w[i] :

i :

1 2 3 4

program hetmany;

const n=8;

var

w:array[1..n] of integer;

i:integer;

procedure init;

{początkowe ustawienie tablicy w}

var i:integer;

begin

w[1]:=1;

for i:=2 to n do w[i]:=0;

end;

function wolne(x,y:integer):boolean;

{sprawdzenie, czy pole <x,y> jest atakowane przez

hetmany ustawione w kolumnach 1,2,...,x-1}

var i:integer;

OK:boolean;

begin

OK:=true; i:=1;

while (i<x) and OK do

if (w[i]-i=y-x) or (w[i]+i=y+x) or (w[i]=y) then

OK:=false else inc(i);

wolne:=OK

end;

function ustawhetmany:integer;

{funkcja realizuje algorytm z nawrotami; jeśli uda się

ustawić n hetmanów, funkcja przyjmuje wartość n+1;

w przeciwnym razie przyjmuje wartość 0}

var k:integer;

begin

k:=2;

while (k<=n) and (k>=1) do

begin

repeat

inc(w[k])

until (w[k]>n) or wolne(k,w[k]);

if (w[k]<=n) then inc(k)

else begin w[k]:=0; dec(k) end;

end;

ustawhetmany:=k

end;

begin

init;

if ustawhetmany=n+1 then

begin

writeln;

for i:=1 to n do write(w[i]:3)

end else writeln('nie mozna rozstawic hetmanow');

end.



Wyszukiwarka

Podobne podstrony:
ukl 74xx, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych, Archit
I kolokwium, Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych, kolokwia i
I kolokwium(1), Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych, kolokwi
wyk.9, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych, Assembler
Sprawozdanie 2, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych,
II1 kolokwium, Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych, kolokwia
wyk.7.1, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych, Assembl
I1 kolokwium, Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych, kolokwia
II kolokwium, Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych, kolokwia
wyk.7, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych, Assembler
II kolokwium(1), Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych, kolokw
wyk.8, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych, Assembler
wyklad AiSD, Informatyka PWr, Algorytmy i Struktury Danych, Algorytmy i Struktury Danych
ukl 74xx, Informatyka PWr, Algorytmy i Struktury Danych, Architektura Systemów Komputerowych, Archit
Algorytmy i struktury danych Wykład 1 Reprezentacja informacji w komputerze
cw 0 1, pwr, informatyka i zarządzanie, Informatyka, algorytmy i struktury danych
ALS - 001-000 - Zadania - ZAJECIA, Informatyka - uczelnia, WWSI i WAT, wwsi, SEM II, Algorytmy i Str
kolokwium1sciaga, Studia Informatyka 2011, Semestr 2, Algorytmy i struktury danych
ALS - 009-005 - Program Sortowanie INSERTION SORT, Informatyka - uczelnia, WWSI i WAT, wwsi, SEM II,

więcej podobnych podstron