Sunteți pe pagina 1din 14

Algoritmul lui Lee

 Ce este si ce face acest algoritm?

Ei bine, algoritmul lui Lee este un algoritm ce determina numarul minim de pasi, pentru a ajunge din punctul x
in punctul y in anumite conditii (de exemplu: evitand obstacole). De-asemenea cu acest algoritm se face
introducerea unei noi structuri in informatica: coada (sau queue). Acest algoritm nu se face la clasa deoarece este
foarte greu de predat, iar explicarea modului de functionare este destul de dificila. Acest algoritm este foarte util
pentru cei ce se afla in clasa 10 si doresc sa participe la olimpiada judeteana de informatica, deoarece este unul
din algoritmii prioritari ce trebuie stiuti (un alt algoritm prioritar ar mai fi algoritmul de fill, dar despre el vom
vorbii intr-un episod viitor). Inainte de a ne apuca sa implementam acest algoritm, vreau sa va spun ca trebuie sa
aveti cateva cunostiinte de baza in limbajul C++.

 Prezentarea generala

Algoritmul lui Lee este defapt o parcurgere in latime (BFS) a unui graf, doar ca aplicat pentru o grila. Stati
linistiti, o sa aflati in clasa 11 ce este aia BFS (sau intr-unul din videourile mele, mai tarziu). Este un algoritm
destul de eficient, avand complexitatea de O(M*N), fiind foarte utilizat in problemele in care apare un labirint.

 Problema alee

Vom incepe sa prezentam acest algoritm, citind o problema “alee” (care defapt este prescurtarea de la a –
algoritm si lee – Lee) de pe platforma infoarena.ro. Daca nu aveti un cont pe infoarena, va trebuii sa va creati
unul. Problema poate fi accesata de pe link-ul http://www.infoarena.ro/problema/alee .
 Vectorii de deplasare

In primul si primul rand, inainte de a incepe sa scriem acest algoritm, va trebui sa ne dam seama cum realizam
deplasarea, in cele 4 sau in cele 8 directii ale axei?.. Dar pentru ca in problema se mentioneaza la “Aleea este
continua daca oricare doua placi consecutive au o latura comuna.”, putem deduce ca deplasarea are loc pe cele 4
directii. Asa ca vom declara doi vectori, primul vector fiind directia pe axa Ox, iar cel de-al doilea directia pe axa
Oy.
Acum vine partea care necesita o atentie mai deosebita, vom codifica cele 4 puncte cardiale in 0 1 si -1. Astfel,
dupa cum urmeaza, avem nordul (0,1), sudul (0,-1), vestul (1,0) si estul (-1,0). Astfel avem liniile

1 int di[4] = {1,0,-1,0};


2 int dj[4] = {0,1,0,-1};

 Citirea valorilor din problema

Acum vom trece la citirea valorilor si initializarea problemei. Astfel incat vom avea N, latimea si lungimea
parcului, M – numarul de obstacole, iar mai apoi citim obstacolele si coordonatele de pornire si oprire.

 Variabila pair
Pair este o variabila ceva mai deosebita, iti permite sa retii doua valori simultan, ceea este perfect pentru
problema noastra, deoarece putem retine coordonata x si coordonata y in aceeasi variabila. Pentru a va arata un
exemplu concret, vom memora punctul P. Il vom declara

1 pair < int, int > P;

Iar pentru a introduce valori, scriem:

1 P = make_pair(1,5);

Iar pentru a afisa: unde .first reprezinta primul numar (adica 1) iar second al doilea numar (5).

1 cout << P.first << “ “ << P.second;

 Clasa queue
Mai departe, pentru rezolvarea acestei probleme ne vom folosii de un include foarte util in rezolvarea tuturor
problemelor, un include care introduce un nou tip de variabila, o variabila cunoscuta la scoala sub numele de
“coada”. Aceasta coada functioneaza pe principiul “primul venit – primul servit” – exact ca o coada de la
farmacie. Incepem prin a scrie header-ul

1 #include <queue>

Si vom analiza urmatoare secventa de cod.

1 queue < int > Q;


2 Q.push(1); Q.push(15); Q.push(25); Q.push(62);
3 cout << Q.front();
4 Q.pop();
5 cout << Q.front();

 Functia OK

Iar ultimul detaliu inainte de a trece la implementarea efectiva a algoritmului. Vom scrie o functie de tip bool
care va verifica daca se poate trece la un nou punct de pe harta sau nu.
1 bool OK(int i, int j)
2{
3 if (i < 1 || j < 1 || i > N || j > N)
4 return false;
5 if (parc[i][j] == -1)
6 return false;
7 return true;
8}

 Algoritmul lui Lee

Inainte de a trece la implementarea efectiva a algoritmului, va trebuii sa urmariti urmatoarea animatie. O prima
observatie este faptul ca algoritmul nostru nu se opreste decat atunci cand a aflat cea mai mica distanta pornind
din punctul nostru la toate celalalte puncte, de unde putem concluziona faptul ca acesta se executa pana nu mai
are puncte, iar rezultatul final (adica numarul minim de pasi) se va afla in coordonata i si j a punctului de oprire
din matrice.

 Vom incepe prin a marca punctul din matrice cu “1” si sa il introducem in queue.
 Iar acum, vine cea mai importanta parte a algoritmului, vine algoritmul in sine. Vom pune cei 4 vecini ai
punctului curent in queue (coada), si ii vom marca cu +1 (deoarece distanta se mareste cu o unitate), iaA

#include <iostream>

using namespace std;


int viz[100];

struct poz

int lin,col;

} c[100];

int main()

int x[100][100],pi,ps,i,j,n,o,m,psi,psj,pci,pcj;

const int dl[]= {0,-1,0,1,0},dc[]= {0,0,1,0,-1};

cin>>n>>m;

for(i=1; i<=n; i++)

for(j=1; j<=m; j++)

cin>>x[i][j];

for(i=1;i<=m;i++)

x[0][i]=x[n+1][i]=-1;

for(i=1;i<=n;i++)
x[i][0]=x[i][m+1]=-1;

cin>>psi>>psj>>pci>>pcj;

c[1].lin=psi;

c[1].col=psj;

pi=ps=1;

x[psi][psj]=1;

while(ps<=pi&&x[pci][pcj]==0)

for(i=1; i<=4; i++)

if(x[c[ps].lin+dl[i]][c[ps].col+dc[i]]==0)

pi++;

c[pi].lin=c[ps].lin+dl[i];

c[pi].col=c[ps].col+dc[i];

x[c[pi].lin][c[pi].col]=x[c[ps].lin][c[ps].col]+1;

}
ps++;

for(i=1;i<=n;i++)

for(j=1;j<=m;j++)

cout<<x[i][j]<<" ";

cout<<"\n";

cout<<x[pci][pcj];

return 0;

Aplicatii

Se citeste o matrice nXm care contine litere mici si apoi un cuvant s. Gasiti cel mai lung prefix al cuvantului s care se poate construi cu literele
din matrice prin deplasare paralela cu liniile si coloanele matricii fara a trece de doua ori prin aceeasi litera.
Exemplu:
56
axsads
aanama
nnaair
asdydi
sedrft
anamariana
prefixul este anamaria
#include<fstream>
using namespace std;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
char a[100][100],s[50];
int n,m,i,j,maxx;
ifstream f("r.in");
ofstream fout("r.out");

int inside(int i,int j)


{
return i>=1 && i<=n && j>=1 && j<=m;
}

void lee(int i,int j)


{ int k,inou,jnou,pas=1,gasit;
int b[100][100]={0};
b[i][j]=1;
do
{ gasit=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j]==s[pas-1] && b[i][j]==pas)
for(k=0;k<4;k++)
{ inou=i+dx[k];
jnou=j+dy[k];
if(inside(inou,jnou) && a[inou][jnou]==s[pas] && b[inou][jnou]==0)
{
gasit=1;
b[inou][jnou]=pas+1;
}
}
pas++;
}
while(gasit);
if(pas-1>maxx) maxx=pas-1;
}

int main()
{ f>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
f>>a[i][j];
f>>s;

for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j]==s[0])
{
lee(i,j);
}
for(i=0;i<maxx;i++) fout<<s[i];
return 0;
}

//sau cu coada

#include<fstream>
using namespace std;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
struct poz { int i,j;};
char a[100][100],s[1000];
int n,m,i,j,maxx;
ifstream f("r.in");
ofstream fout("r.out");

int inside(int i,int j)


{
return i>=1 && i<=n && j>=1 && j<=m;
}

void lee(int i, int j)


{ int k,inou,jnou,pas=1,st,dr,gasit;
poz x[10000];
int pus[100][100]={0};
x[1].i=i;
x[1].j=j;
st=dr=1;
do
{
gasit=0;
i=x[st].i;
j=x[st].j;
for(k=0;k<4;k++)
{ inou=i+dx[k];
jnou=j+dy[k];
if(inside(inou,jnou) && a[inou][jnou]==s[pas] && !pus[inou][jnou])
{
dr++;
pus[inou][jnou]=1;
x[dr].i=inou;
x[dr].j=jnou;
gasit=1;
}
}
if(gasit) pas++;
st++;
}
while(gasit || st<=dr);
if(pas>maxx) maxx=pas;
}

int main()
{ f>>n>>m;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
f>>a[i][j];
f>>s;

for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(a[i][j]==s[0])
lee(i,j);
for(i=0;i<maxx;i++) fout<<s[i];
return 0;
}
2. Muzeu
Un muzeu are forma patratica si contine N*N camere ce pot fi vizitate. Unele camere sunt deschise si contin opere de arta, altele sunt inchise
(sunt folosite pentru alte scopuri). In unele din camerele libere, se afla paznici. Directorul muzeului se teme de eventualitatea unei spargeri si
de aceea doreste sa evalueze cat de bine au fost asezati paznicii in camerele libere. Mai precis, el doreste sa afle, pentru fiecare camera
libera, care este distanta minima pana la cel mai apropiat paznic (numarul minim de camere prin care trebuie sa intre un paznic pentru a
ajunge la camera respectiva). Paznicii se pot deplasa numai in camerele libere din Nord, Est, Sud sau Vest (cu conditia sa nu paraseasca
muzeul).

Date de Intrare
Pe prima linie a fisierului muzeu.in se afla numarul intreg N, reprezentand numarul de linii (si de coloane) ale muzeului (muzeul
avand N*N camere). Urmatoarele N linii contin cate Ncaractere fiecare:

 `.' pentru camera libera in care nu se afla paznic

 `P' pentru camera libera in care se afla paznic

 `#' pentru camera inchisa (prin care nu pot trece nici paznicii, dar in care nu pot intra nici hotii)

Date de Iesire
In fisierul muzeu.out veti afisa N linii, fiecare din ele continand N numere intregi (separate prin spatii). Fiecare numar afisat corespunde
camerei de pe linia si coloana corespunzatoare din fisierul de intrare. Pentru fiecare camera libera veti afisa distanta minima pana la cel mai
apropiat paznic (sau -1 daca nici un paznic nu poate ajunge in aceasta camera). Pentru camerele inchise, veti afisa -2.

Restrictii si precizari
 1 ≤ N ≤ 250

Exemplu
muzeu.in muzeu.out
8 -1 -1 -1 -2 2 3 4 5

...#.... -2 -1 -1 -2 1 2 -2 6

#..#..#. 8 -2 -2 1 0 1 2 -2

.##.P..# 7 6 -2 2 -2 2 -2 6

..#.#.#. 6 5 4 3 4 3 4 5

........ 6 5 4 3 4 4 5 6

........ -2 -2 -2 2 3 4 -2 -2

###...## 2 1 0 1 2 3 4 5

..P.....

Rezolvare
Această problemă se rezolvă cu algoritmul lui Lee, doar că în coadă vom pune iniţial nu o coordonată, ci toate coordonatele paznicilor. Pentru
asta se citesc ca şir de caractere fiecare caracter în parte, şi se convertesc acestea (la citire) în numere astfel: zidurile (#) vor fi notate cu -2,
paznicii (P) cu -1, iar căile libere cu 0. După executarea algoritmului, se verifică şi se înlocuiesc cifrele de 0 cu -1 (pentru că în problemă ne
cere să afişăm cu -1 locurile care nu au fost vizitate), iar cifrele de -1 (reprezentând paznicii) cu 0. Aveţi un exemplu de citire transpus în
pseudocod:
?

1
citeşte m
2 pentru i=1,m

3 pentru j=1,m

4 început

5 citeşte s //variabila cu care citim caracterele pentru a le putea converti

dacă (s=='#') ct[i][j]=-2 //convertim caracterul în cifre


6
altfel dacă (s=='.') ct[i][j]=0; //-----------------------------
7
8 altfel dacă (s=='P') ct[i][j]=-1; //-----------------------------

9 dacă (ct[i][j]==-1) //verificăm dacă există un paznic

început
10
q[l].st=i; //punem paznicul în coadă
11
q[l].dr=j; //-----------------------
12
l++; //contorul cu care numărăm paznicii
13
sfârşit(dacă)
14
sfârşit(pentru)
15 q1=l; //contorul pe care îl folosim pentru a număra şi a pune în coadă locur

16

S-ar putea să vă placă și