Metoda Divide Et Impera (DEI)
Metoda Divide Et Impera (DEI)
DA NU
Sf – încep <= 1
DA M1<M2 NU
MINIM := M 1 MINIM := M 2
Main
min := MINIM ( 1, n, X )
Tipăreşte min
STOP
1
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
program Determinare_Minim;
uses CRT;
type
vector = array [1 .. 10] of REAL;
VAR
x : vector;
min : REAL;
n, i : integer;
begin {Main}
CLRSCR;
writeln (‘Precizati cate elemente are vectorul’);
write ('n = ');
readln (n);
2
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
Incep := 1
Sf := n
GASIT := FALSE
DA Incep <= Sf NU
SI
GASIT = FALSE
mij := ( Incep + Sf ) DIV 2
DA NU
Elem = X [mij]
DA NU
GASIT = TRUE
STOP
3
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
Program Căutare_Binară_Iterativă_Fără_Subprogram ;
CONST
Nmax = 100;
type
vector = array [1.. Nmax] of REAL;
VAR
x : vector;
mij, n, i, încep, sf : integer;
elem : REAL;
GASIT: boolean; { GASIT = TRUE dacă elementul a fost găsit şi FALSE, dacă nu}
Begin
CLRSCR;
REPEAT
Write (‘Dati numarul de elemente ale vectorului, n = ’);
readln (n);
UNTIL (n >= 1) AND (n <= Nmax);
for i := 1 to n do
begin
write ('x [ ', i,' ] = ');
readln (x [i]);
end;
writeln;
încep := 1;
sf := n;
GASIT:= FALSE;
while (încep <= sf) AND (GASIT = FALSE) do
begin
mij := (încep + sf) DIV 2;
if elem = x [mij] then
GASIT := TRUE
else
if elem < x [mij] then
sf := mij - 1
else
încep := mij + 1
end; {sfârşit WHILE}
if GASIT = TRUE then {sau if GASIT then}
writeln (elem,' există')
else
writeln (elem,' nu există');
readln
end.
4
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
START
GASIT := FALSE
DA NU
Elem = X [mij]
DA NU
GASIT := TRUE Elem < X [ mij ]
Main
CAUTA ( 1, n, GASIT )
DA NU
GASIT = TRUE
STOP
5
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
program Căutare_Binară_Varianta_Recursivă;
uses CRT;
CONST
Nmax = 100;
type
vector = array [1.. Nmax] of REAL;
VAR
x : vector ;
elem : REAL ;
n, i : integer ;
GASIT : boolean ; {GASIT = TRUE dacă elementul a fost găsit şi FALSE dacă nu}
procedure CAUTA ( încep, sf : integer; VAR GASIT : boolean ) ;
var
mij : integer;
begin
IF încep <= sf then
begin
mij := (încep + sf) DIV 2;
if elem = x [mij] then
GASIT := TRUE
else
if elem < x [mij] then
CAUTA ( încep, mij-1, GASIT)
else
CAUTA (mij +1, sf, GASIT)
end
ELSE
GASIT := FALSE
end; {sfârşit procedură}
begin {Main}
CLRSCR;
REPEAT
Write (‘Dati numărul de elemente ale vectorului, n = ’);
readln (n);
UNTIL (n >= 1) AND (n <= Nmax);
writeln (‘Introduceti vectorul ordonat crescator’);
for i := 1 to n do
begin
write ('x [ ', i,' ] = ');
readln (x [i]);
end;
writeln;
write ('Daţi elementul căutat, elem = ');
readln (elem);
CAUTA (1, n, GASIT);
if GASIT = true then
writeln (elem,' există')
else
writeln (elem,' nu există');
readln
end.
6
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
10. 3. Interclasarea
Se dau doi vectori A (m) şi B (n) ordonaţi. Să se interclaseze (să se construiască un al treilea vector
C (m + n), ordonat, care conţine toate elementele vectorilor A şi B).
Prezentăm doi algoritmi de interclasare asemănători.
START
Interclasare - Varianta 1
Introduceti m, n ( nr. de elemente ale vectorilor A şi B )
K := 0
i := 1
20 10 j := 1 30
DA NU
A [ i ] <= B [ j ]
K := K + 1 K := K + 1
C [ k ] := A [ i ] C [ k ] := B [ j ]
40 50 j := j + 1
i := i + 1
NU DA j > n NU
i <= m
DA j <= n NU DA i <= m NU
K := K + 1 K := K + 1
C [ k ] := B [ j ] C [ k ] := A [ i ]
j := j + 1 i := i + 1
60
K := 1
DA NU
K <= m + n
Tipăreşte C [ K ] STOP
K := K + 1
7
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
Program INTERCLASARE_1 ;
Label 10, 20, 30, 40, 50, 60 ;
Const nmax = 50;
Type vector = array [1 .. nmax] of REAL;
Var A, B : vector;
C : array [1 .. 2 * nmax] of REAL;
i, j, m, n, k : integer;
Begin
REPEAT
write ('Introduceţi m = '); readln (m);
UNTIL (m >= 1) AND ( m <= Nmax);
REPEAT
write ('Introduceţi n = '); readln (n);
UNTIL (n >= 1) AND ( n <= Nmax);
writeln (‘Dati vectorul A’);
for i := 1 to m do
begin
write ('A [i] = '); readln (A [i] )
end;
writeln (‘Dati vectorul B’);
for j := 1 to n do
begin
write ('B [j] = '); readln (B [j])
end;
k := 0; {index pentru elementele lui C}
i := 1; {index pentru elementele lui A}
j := 1; {index pentru elementele lui B}
10: if A [i] <= B [j] then
GOTO 20
else
GOTO 30;
20: k := k + 1; C [k] := A [i]; i := i + 1;
if i <= m then
GOTO 10
else
GOTO 40;
30: k := k + 1; C [k] := B [j]; j := j + 1;
if j > n then
GOTO 50
else
GOTO 10;
40: while j <= n do
begin
k := k + 1; C [k] := B [j]; j := j + 1;
end;
GOTO 60;
50: while i <= m do
begin
k := k + 1; C [k] := A [ i ]; i := i + 1;
end;
60: writeln (‘Vectorul rezultant este:’);
for k := 1 to m + n do
writeln ('C [',k,'] = ', C [k]); readln
end.
Observaţie: Varianta 1 a algoritmului de interclasare este mai greu de urmărit, datorită folosirii
instrucţiunii GOTO.
8
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
Iată şi o variantă mai clară, mai bine structurată a algoritmului de interclasare.
Interclasare - Varianta 2
START
K := 0
i := 1
j := 1
i <= m
DA NU
SI
j <= n
DA NU DA
A[i]<=B[j] i <= m NU
K := K + 1 K := K + 1 K := K + 1
C [ k ] := A [ i ] C [ k ] := B [ j ] C [ k ] := A [ i ]
DA j <= n NU
i := i + 1 j := j + 1 i := i + 1
K := K + 1
C [ k ] := B [ j ]
j := j + 1
K := 1
DA K <= m + n NU
Tipăreşte C [ K ] STOP
K := K + 1
9
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
program INTERCLASARE_2;
const Nmax = 30;
type vector = array [1 .. Nmax] of REAL;
var A, B : vector;
C : array [1 .. 2 * Nmax] of REAL;
i, j, m, n, k : integer;
begin
REPEAT
write ('Introduceti nr. de elemente pentru vectorul A, m = '); readln (m);
UNTIL (m >=1) AND (m <= Nmax);
REPEAT
write ('Introduceti nr. de elemente pentru vectorul B, n = '); readln (n);
UNTIL (n >=1) AND (n <= Nmax);
10
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
program MERGE_SORT;
CONST Nmax = 50;
TYPE vector = array [1 .. Nmax] of REAL;
VAR
n, i: integer;
A, : vector;
procedure INTERCLASEAZA (încep, mij, sf : integer; var A: vector );
var
i, j, k : integer ;
C : vector ; { C = vector auxiliar folosit în procedură }
begin
i := încep; { index pentru elementele primei jumătăţi a vectorului A }
j := mij + 1; { index pentru elementele celei de-a doua jumătăţi a vectorului A }
k := 0; { index pentru elementele vector auxiliar C }
while ( i <= mij ) AND ( j <= sf ) do
begin
if A [i] <= A [j] then
begin
k := k + 1;
C [k] := A [i];
i := i + 1;
end
else
begin
k := k + 1;
C [k] := A [j];
j := j + 1
end;
end;
while i <= mij do
begin
k := k + 1;
C [k] := A [i];
i := i + 1
end;
while j <= sf do
begin
k := k + 1;
C [k] := A [j];
j := j + 1
end;
11
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
k := 1;
for i := încep to sf do { REFACERE vector A SORTAT }
begin
A [i] := C [k] ;
k := k + 1
end;
end; { sfârşit procedură }
12
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
START
i <= mij
SI NU
j <= sf
DA NU DA
A[i]<=A[j] i <= mij NU
K := K + 1 K := K + 1 K := K + 1
C [ k ] := A [ i ] C [ k ] := A [ j ] C [ k ] := A [ i ]
DA j <= sf NU
i := i + 1 j := j + 1 i := i + 1
K := K + 1
C [ k ] := A [ j ]
j := j + 1
K := 1
i := Încep
DA i <= sf NU
REFACEREA
VECTORULUI A [ i ] := C [ K ] Sf. proc
A ORDONAT
K := K + 1
i := i + 1
13
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
Def. procedura ORDONEAZA ( Încep, Sf : integer; VAR A : vector )
DA NU
Sf – Încep <= 1
A [ Sf ] := AUX
INTERCLASEAZA ( Încep, mij, Sf, A )
Sf. proced.
Main
ORDONEAZA ( 1, n, A)
STOP
START
DA NU
Încep < Sf Dacă Început = Sf, nu
Atenţie ! are sens interschimbarea
“Strict mai mare”. i := Încep X [ Încep ] <-> X [ Sf ].
În caz contrar, Deci, algoritmul va
“Stack overflow”. j := Sf continua doar dacă
Încep < Sf.
B := TRUE Condiţia de oprire ar
trebui să fie scrisă
Încep >= Sf
dar este scrisă
DA NU
X[i] > X[j] Încep < Sf
pentru a avea ramura
AUX := X [ i ] “DA” a IF-ului ocupată.
X [ i ] := X [ j ]
X [ j ] := AUX
B := NOT B
Xi > Xj
Xi < X j Se interschimbă Xi <-> Xj,
Se păstrează i se ocupă o poziţie i şi se
şi se alege alt j DA NU trece la următorul i
B = TRUE
j := j – 1 i := i + 1
DA i = j NU
i<j
QUICK (Încep, i , X )
QUICK ( i + 1, Sf, X )
Main
QUICK ( 1, n, X )
STOP
15
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
Program QUICK_SORT;
CONST Nmax = 50;
TYPE vector = array [1 .. Nmax] of REAL;
VAR x : vector;
i, n : integer;
procedure QUICK (Încep, Sf : integer; VAR X : vector);
VAR
i, j : integer;
aux : REAL;
B : BOOLEAN;
begin
if Încep < Sf then {Conditia de oprire}
begin
i := Încep;
j := Sf;
B := TRUE;
repeat
if X [ i ] > X [ j ] then
begin
aux := X [ i ];
X [ i ] := X [ j ];
X [ j ] := aux;
B := not B;
end;
if B = TRUE then
j := j - 1
else
i := i + 1;
until i = j;
QUICK ( Încep, i, X );
QUICK ( i + 1, Sf, X );
end;
end;
begin {Main}
repeat
write ('n = '); readln (n)
until ( n >= 1) and (n <= Nmax);
write ('Introduceţi elementele vectorului');
for i := 1 to n do
begin
write (' X [ ', i, ' ] = '); readln ( X [ i ] );
end;
writeln ('Vectorul iniţial :');
for i := 1 to n do
write ( X [ i ],' ');
QUICK ( 1, n, X );
writeln ('Vectorul sortat este :');
for i := 1 to n do
write ( X [ i ],' ');
readln;
end.
16
Cătălin Tănase Algoritmi şi limbaje de programare - Note de curs
În Anexa 3 sunt prezentate alte aplicaţii ale metodei DEI: Problema tăieturilor, Suma elementelor unui
vector.
Concluzii
Metoda de programare Divide et Impera (“Dezbină şi stăpâneşte” – principiul de guvernare
enunţat de Machiavelli în formularea Divide Ut Regnes – „dezbină pentru a domni”) constă în
împărţirea unei probleme iniţiale de o anumită dimensiune în două sau mai multe subprobleme de
acelaşi tip şi de dimensiuni mai reduse. Se presupune că fiecare dintre problemele în care a fost
descompusă problema iniţială se poate descompune în alte subprobleme, la fel cum a fost descompusă
problema iniţială, sau se reduc la o problemă banală. Împărţirea în subprobleme are loc până când
dimensiunea acestora devine suficient de mică pentru a fi rezolvate în mod direct (cazul de bază,
probleme care admit o rezolvare imediată). După rezolvarea subproblemelor, se execută faza de
combinare a rezultatelor, în vederea rezolvării întregii probleme.
Metoda Divide Et Impera se poate aplica în rezolvarea unei probleme care îndeplineşte
următoarele condiţii:
1. problema iniţială se poate descompune în două sau mai multe subprobleme ;
2. aceste subprobleme sunt independente una faţă de alta (o subproblemă nu se rezolvă pe baza alteia
şi nu foloseşte rezultatele celeilalte) ;
3. subproblemele sunt similare cu problema iniţială;
4. la rândul lor, subproblemele se pot descompune (dacă este necesar) în alte subprobleme mai simple;
5. aceste subprobleme simple se pot soluţiona imediat prin algoritmul simplificat.
Deoarece puţine probleme îndeplinesc condiţiile de mai sus, aplicarea metodei este destul de rară.
Complexitatea algoritmilor bazaţi pe metoda Divide et Impera este în general bună (de multe
ori pătratică, chiar n * log (n) sau logaritmică).
Etapele rezolvării unei probleme în cadrul acestei metode sunt :
descompunerea problemei iniţiale în subprobleme independente, similare problemei de bază, de
dimensiuni mai mici;
descompunerea treptată a subproblemelor în alte subprobleme din ce în ce mai simple, până când se
pot rezolva imediat, prin algoritmul simplificat;
rezolvarea subproblemelor simple;
combinarea soluţiilor găsite, pentru construirea soluţiilor subproblemelor de dimensiuni din ce în ce
mai mari ;
combinarea ultimelor soluţii determină obţinerea soluţiei problemei iniţiale.
Întrucât metoda este, în esenţă, recursivă, ea se implementează cel mai natural folosind
subprograme recursive. Dacă dorim, totuşi, o implementare iterativă, va trebui să folosim în program o
stivă pe care să o gestionăm explicit şi în care să încărcăm subproblemele apărute şi nerezolvate.
17