Sunteți pe pagina 1din 26

156

15. Tehnici de programare


15.1. Metoda Greedy
Algoritmii Greedy (grccdy lacom) sunt n gcncral simpli i sunt
Iolosi i n problcmc dc optimizarc n carc sc poatc ob inc optimul global n
alegeri succesive ale optimului local, ceea ce permite rezolvarea problemei fr
nici o revenire la deciziile anterioare. n acest sens avem:
o mul imc dc FDQGLGD L
o Iunc ic carc vcriIic dac o anumit mul imc dc candida i constituic o
VROX LHSRVLELO, nu neaprat optim, a problemei
o Iunc ic carc vcriIic dac o mul imc dc candida i cstc fezabil, adic dac
este posibil s completm aceast mul imc astIcl nct s ob incm o solu ic
posibil, nu neaprat optim, a problemei
o IXQF LHGHVHOHF LH care indic la orice moment care este cel mai promi tor
dintrc candida ii nc nefolosi i
o IXQF LHRELHFWLY care d valoarea unei solu ii; accasta cstc Iunc ia pc carc
dorim s o optimizm (minim/maxim).
Modelul general de problem tip Greedy
Se d o mul imc A. Sc ccrc o submul imc B (B A) care s
ndeplineasc anumite condi ii i s optimizeze func ia obicctiv. Dac o
submul imc C ndcplinctc accstc condi ii atunci C cstc o solu ic posibil. Este
posibil ca n unele probleme s existe mai multe solu ii posibilc, caz n carc sc
cere o ct mai bun solu ic, cvcntual chiar solu ia optim, adic solu ia pcntru
care se realizeaz maximul sau minimul unei func ii obicctiv.
157
Pentru ca o problem s poat fi rezolvat prin metoda Greedy trebuie s
ndeplineasc urmtoarea condi ic: dac B este o solu ic posibil i C B
atunci C cstc dc ascmcnca o solu ic posibil.
Construc ia solu ici sc rcalizcaz pas cu pas astfel:
ini ial, mul imca B a candida ilor sclccta i cstc vid
la fiecare pas se ncearc adugarea celui mai promi tor candidat la
mul imca B, conIorm Iunc ici dc sclcc ic
dac dup o astfel de adugare, mul imca B nu mai cstc Iczabil, se elimin
ultimul candidat adugat; acesta nu va mai fi niciodat luat n considerare
dac dup o astfel de adugare, mul imca B cstc Iczabil, ultimul candidat
adugat va rmne n mul imca B
la fiecare astfel de pas se va verifica dac mul imca B cstc o solu ic posibil
a problemei.
Dac algoritmul este corect, prima solu ic gsit va fi ntotdeauna o
solu ic optim, dar nu neaprat unica (se poate ca func ia obicctiv s aib
acccai valoarc optim pcntru mai multc solu ii posibilc).
Descrierea formal a unui algoritm Greedy general este:
Algoritmul Greedy (A) este:
B := ;
CtTimp NOT Solu ic (B) AND A Exectut
x := Select(A);
A := A - {x};
Dac Fezabil(B {x}) Atunci B := B {x}
SfDac
SfCt
Dac Solu ic(B) Atunci B cstc solu ic
Altfel Nu exist solu ic
SfDac
SfAlgoritm
158
Solu ic(B) - Iunc ic carc vcriIic dac o mul imc dc candida i c o solu ic
posibil;
Sclcct(A) - Iunc ic dcrivat din func ia obicctiv
Fczabil(B) - Iunc ic carc vcriIic dac o mul imc dc candida i cstc Iczabil.
Aceast metod este util n rezolvarea problemelor n care se cere s se
aleag o mul imc dc clcmcntc carc s satisfac anumite condi ii i s realizeze
un optim: s se gseasc cea mai bun ordine de efectuare a unor lucrri ntr-un
timp minim, s se gseasc cel mai scurt drum ntr-un graf, problema restului
cu numr minim dc monczi, intcrclasarca optim a irurilor ordonatc, problcma
comis-voiajorului, problema rucsacului.
Exemplu:
Vom considera ca exemplu problema rucsacului:
Se d un rucsac de capacitate Volum i un numr dc n obiecte,
specificndu-se volumul obiectelor (vectorul Obiecte). Se cere un program care
s determine varianta de introducere a obiectelor n rucsac, astfel nct s
ncap ct mai multe obiecte.
Rezolvare:
Pentru aceast problem, o solu ic cstc acccptabil, dac suma obiectelor
dcpusc n rucsac nu dcpctc limita maxim Volum. Alegerea unui obiect ce
urmeaz a fi introdus n rucsac se efectueaz cutnd un obiect ct mai redus ca
volum. Dac utilizm varianta mbun-t it a algoritmului, i anumc obicctclc
sunt ordonate descresctor dup volum, naintea introducerii n rucsac atunci
alegerea se face n aceast ordine. Iat n continuare implementarea
algoritmului n Pascal.
159
program Rucsac;
const
MaxObiecte = 100;
var
NrObiecte: Integer;
Obiecte: array[1 .. MaxObiecte] of Integer;
Volum: Integer;
procedure Citeste;
var
I: Integer;
begin
repeat
Write(Volumul rucsacului: );
Readln(Volum)
until Volum > 0;
repeat
Write(Numarul obiectelor: );
Readln(NrObiecte);
until (NrObiecte > 0) and (NrObiecte <= MaxObiecte);
for I := 1 to NrObiecte do
repeat
Write(Volumul obiectului , I, : );
Readln(Obiecte[I]);
until Obiecte[I] > 0;
Writeln;
end;
160
procedure Rezolva;
var
TabIndex: array[1 .. MaxObiecte] of Integer;
VolumDisponibil: Integer;
I, J, Aux: Integer;
begin
{ Indexeaza obiectele in ordinea descrescatoare a volumului }
for I := 1 to NrObiecte do
TabIndex[I] := I;
for I := 1 to NrObiecte - 1 do
for J := I + 1 to NrObiecte do
if Obiecte[TabIndex[I]] < Obiecte[TabIndex[J]] then
begin
Aux := TabIndex[I];
TabIndex[I] := TabIndex[J];
TabIndex[J] := Aux;
end;
{ Parcurge obiectele in ordinea descrescatoare a volumului }
Writeln(Continutul posibil al rucsacului:);
VolumDisponibil := Volum;
for I := 1 to NrObiecte do
if Obiecte[TabIndex[I]] <= VolumDisponibil then
begin
VolumDisponibil := VolumDisponibil - Obiecte[TabIndex[I]];
Writeln(Obiectul , TabIndex[I], de volum , Obiecte[TabIndex[I]]);
end;
if VolumDisponibil < Volum then
Writeln(Volum ramas neocupat: , VolumDisponibil)
else
161
Writeln(Nu incape nici un obiect in rucsac.);
Writeln;
end;
begin
Citeste;
Rezolva;
end.
15.2. Metoda Divide et Impera
Divide et Impera este o metod ce const n:
descompunerea problemei ce trebuie rezolvat ntr-un numr de
subproblcmc mai mici alc acclciai problcmc
rczolvarca succcsiv i indcpcndcnt a Iiccrcia dintrc subproblcmc
rccompuncrca subsolu iilor astIcl ob inutc pcntru a gsi solu ia problcmci
ini ialc.
Modelul general al metodei Divide et Impera
Algoritmul Divide_et_Impera(x) este:
{ returneaz o solu ic pcntru cazul x }
Dac x este suficient de mic atunci adhoc(x) SfDac
{descompune x n subcazurile x
1
,x
2
,,x
k
}
Pentru i:=1,k execut y
i
:= divimp(x
i
) SfPentru
{recompune y
1
,y
2
,,y
k
n scopul ob incrii solu ici y pcntru x}
Rezultate: y
162
unde:
adhoc - este subalgoritmul de baz pentru rezolvarea subcazurilor mici
ale problemei n cauz
divimp - mparte probleme n subprobleme.
Un algoritm divide et impera trebuie s evite descompunerea recursiv a
subcazurilor suficient de mici, deoarece pentru acestea este mai eficient
aplicarea direct a algoritmului de baz. Cnd se poate ns decide c un caz
este suficient de mic?
n general, se recomand o metod hibrid care const n:
- determinarea teoretic a formulei recurente
- gsirea empiric a valorilor constante folosite de aceste formule n
Iunc ic dc implcmcntarc.
Se observ c aceast metod este prin defini ic rccursiv. Uneori este
posibil eliminarea recursivit ii printr-un ciclu itcrativ.
Exemplu:
S considerm problema turnurilor din Hanoi:
Se dau 3 tije. Pe prima tij se gsesc Nr discuri, aczatc unul pcstc altul
n ordine descresctoare a diametrului lor. Se cere s se mute cele Nr discuri pe
a 3-a tij, innd cont c la orice mutare un disc se poate pune pe o tij liber
sau pc una carc con inc doar discuri cu diamctrul mai marc ca al su.
Rezolvare: Fie cele 3 tije botezate Sursa, Destinatie i Intermediar.
Problema este descompus n felul urmtor:
trebuie mutate Nr-1 discuri de pe tija Sursa pe tija Intermediar, folosind
ca intermediar tija Destinatie
se mut un disc (ultimul) de pe tija Sursa pe tija Destinatie
trebuie mutate Nr-1 discuri de pe tija Intermediar pe tija Destinatie,
folosind ca intermediar tija Sursa.
163
Implementarea n Pascal este dat n continuare:
program TurnurileDinHanoi;
var
Nr: Integer;
procedure Muta(const Sursa, Destinatie: string);
const
Mutare: Integer = 0;
begin
Mutare := Mutare + 1;
Writeln(Mutare : 5, ' : muta din ', Sursa, ' in ', Destinatie);
end;
procedure Rezolva(Nr: Integer; const Sursa, Intermediar, Destinatie: string);
begin
if Nr = 1 then
Muta(Sursa, Destinatie)
else
begin
Rezolva(Nr - 1, Sursa, Destinatie, Intermediar);
Muta(Sursa, Destinatie);
Rezolva(Nr - 1, Intermediar, Sursa, Destinatie);
end;
end;
164
begin
repeat
Write(Numarul discurilor: );
Readln(Nr);
until Nr > 0;
Rezolva(Nr, stanga, mijloc, dreapta);
end.
15.3. Metoda backtracking
Metoda backtracking (cutare cu revenire) se poate utiliza atunci cnd
solu ia problcmci sc poatc rcprczcnta sub Iorma unui vcctor X (x
1
,x
2
,,x
n
)
S = S
1
xS
2
xxS
n
, unde S este VSD LXO WXWXURU YDORULORU SRVLELOH, iar S
i
sunt
mul imi Iinitc ordonatc (1 i n). Mul imca solu iilor rczultat sc dcIinctc
astfel:
R = {XS| X ndcplinctc FRQGL LLOHLQWHUQH}
&RQGL LLOH LQWHUQH sunt rcla ii ntrc componcntclc x
1
,x
2
,,x
n
ale unui
vector X pe care trebuie s le ndeplineasc acestea pentru ca vectorul X s fie
solu ic acccptabil (corect). Condi iilc intcrnc sunt spcciIicc Iiccrei probleme.
ntr-o problem se pot cere toate solu iilc acccptabilc ca rczultatc sau sc poatc
alcgc o solu ic carc maximizcaz sau minimizeaz o func ic obicctiv dat. Prin
metoda backtracking nu se genereaz toate valorile posibile, deci nu se
determin to i vcctorii X din S. Sc complctcaz vectorul X secven ial; sc
atribuie componentei x
k
o valoare numai dup ce au fost atribuite deja valori
componentelor x
1
,x
2
,,x
k-1
. Nu se va trece la componenta x
k+1
, dect dac sunt
verificate FRQGL LLOHGHFRQWLQXDUH pentru x
1
,x
2
,,x
k
.
&RQGL LLOH GH FRQWLQXDUH dau o condi ic ncccsar pentru a ajunge la
rezultat cu primele k alegeri fcute. Altfel spus, dac condi iilc dc continuarc
nu sunt satisfcute, atunci oricum am alege valori pentru urmtoarele
165
componente x
k+1
,x
k+2
,,x
n
, nu vom ajungc la o solu ic acccptabil, deci nu are
sens s continum completarea vectorului X. Se poate observa c cu ct aceste
condi ii dc continuarc sunt mai rcstrictivc cu att algoritmul va Ii mai cIicicnt,
deci o bun alegere a condi iilor dc continuarc va ducc la rcduccrca numrului
de cutri.
Exist o strns legtur ntre condi iilc dc continuarc i condi iilc
intcrnc. Condi iilc dc continuarc sc pot considcra ca Iiind o gcncralizarc a
condi iilor intcrnc pcntru oricc subir x
1
,x
2
,,x
k
(1 k n). Aceasta nseamn
c pentru k=n condi iilc dc continuarc coincid cu condi iilc intcrnc. Dac kn i
sunt ndcplinitc condi iilc dc continuarc sc poatc da ca rczultat solu ia X, pcntru
c au fost ndeplinite condi iilc intcrnc. Dac nu sunt ndeplinite condi iilc
interne se alege alt valoare din mul imca S
k
, pentru componenta x
k
, iar dac n
mul imca S
k
nu mai sunt alte valori (pentru c mul imilc sunt Iinitc), atunci sc
revine la componenta anterioar x
k-1
, ncercnd o nou alegere (din mul imca
S
k-1
pentru componenta x
k-1
). Dac s-a ajuns la x
1
i nu sc mai poatc cxccuta o
revenire (k=0), atunci algoritmul se termin cu insucces.
Modelul general al metodei backtracking
Rezolvarea unei probleme prim metoda backtracking se bazeaz pe
urmtorul model:
Algoritmul Backtracking (X,n) este:
k:=1;
x1: primul clcmcnt din mul imca S1;
Repet
Cttimp (k<n) L condi iilc dc continuarc sunt ndcplinitc execut
k:=k+1;
xk: primul clcmcnt din mul imca Sk
SfCttimp
166
Dac (k=n) L condi iilc dc continuarc sunt ndcplinitc atunci
Rezultate X
SfDac
Cttimp (k>0) Ln Sk nu mai sunt alte elemente execut
k:=k-1
SfCttimp
Dac k>0 atunci xk:= urmtorul element din Sk SfDac
Pn cnd k=0
SfAlgoritm.
Exemplu
Considerm urmtoarea problem (Sritura calului):
Sc d o tabl dc ah. Sc ccrc s sa gscasc un drum pc carc l parcurgc
un cal carc pornctc dintr-un col i sarc ntr-o pozi ic libcr (n care nu a mai
srit) conIorm mutrii dc la jocul dc ah. n accst mod, calul va trcbui s trcac
prin toate csu clc. n cazul n carc problcma nu arc solu ic sc va aIia un mcsaj
corespunztor.
Rezolvare:
n primul rnd, sc inc dc cont dc modul n carc sc poatc dcplasa un cal
pc tabla dc ah. Fa de o anumit pozi ic, mutrile calului implic modificarea
coordonatclor pc tabla dc ah conIorm matricci Mutari. Apoi, sc pornctc din
col ul dc coordonatc (1,1) i sc va nccrca naintarca. Condi iilc dc continuarc
con in: calul s nu dcpcasc marginilc tablci i pozi ia pc carc o va ocupa n
urma mutrii s nu fie deja ocupat. Func ia Rezolva va specifica dac
problcma arc solu ic.
167
program SarituraCalului;
const
MaxDim = 8; { Dimensiunea maxima a tablei de sah }
Mutari: array[1 .. 8, 1 .. 2] of Integer =
((-1, -2), (-1, 2), (1, -2), (1, 2),
(-2, -1), (-2, 1), (2, -1), (2, 1));
var
Tabla: array[1 .. MaxDim, 1 .. MaxDim] of Integer; { Tabla de sah }
Dim: Integer; { Dimensiunea tablei }
NrMutari: Integer; { Numarul mutarilor }
NrSolutii: Integer; { Numarul solutiilor }
{ Afisarea unei solutii gasite }
procedure Afis;
var
I, J: Integer;
begin
for I := 1 to Dim do
begin
for J := 1 to Dim do
Write(Tabla[I, J] : 5);
Writeln;
end;
Writeln;
end;
168
{ Procedura recursiva }
procedure Recurs(X, Y: Integer);
var
DX, DY: Integer; { Coordonatele rezultate in urma deplasarii }
I: Integer;
begin
NrMutari := NrMutari + 1;
Tabla[X, Y] := NrMutari;
if NrMutari = Dim * Dim then
begin
NrSolutii := NrSolutii + 1;
Afis;
end;
for I := 1 to 8 do
begin
DX := X + Mutari[I][1];
DY := Y + Mutari[I][2];
if (DX >= 1) and (DX <= Dim) and (DY >= 1) and (DY <= Dim) and
(Tabla[DX, DY] = 0) then
{ Daca mutarea nu depaseste marginile tablei,
si careul nu a mai fost ocupat inainte }
Recurs(DX, DY);
end;
{ Se retrage mutarea, eliberand careul (X, Y) }
NrMutari := NrMutari - 1;
Tabla[X, Y] := 0;
end;
169
{ Rezolvarea problemei }
function Rezolva: Boolean;
var
I, J: Integer;
begin
if Dim < 3 then
{ Nu se poate efectua nici o mutare }
Rezolva := False
else
begin
{ Initializari }
if Dim > MaxDim then Dim := MaxDim;
for I := 1 to Dim do
for J := 1 to Dim do
Tabla[I, J] := 0;
NrMutari := 0;
NrSolutii := 0;
{ Apelul metodei backtracking }
Recurs(1, 1); { Se porneste din careul stanga-sus }
Rezolva := (NrSolutii > 0);
end;
end;
{ Programul principal }
begin
repeat
Write(Dimensiunile tablei: );
Readln(Dim);
until (Dim > 0) and (Dim <= MaxDim);
if Rezolva then
170
Writeln(NrSolutii, solutii.)
else
Writeln(Problema nu are solutii.);
end.
15.4. Metoda programrii dinamice
Aceast metod de elaborare a algoritmilor se aplic n rezolvarea
problcmclor dc optim pcntru carc solu ia cstc rczultatul unui ir dc dccizii. Ca i
metoda divide et impera, programarea dinamic rezolv problemele combinnd
solu iilc subproblcmclor. Dac subproblemele con in sub-subproblcmc comunc
atunci este mai eficient aplicarea tehnicii programrii dinamice.
Metoda programrii dinamice se caracterizeaz prin trei principii
fundamentale:
cvitarca calculrii dc mai multc ori a accluiai subcaz, prin mcmorarca
rezultatelor intermediare;
programarca dinamic construictc algoritmul dc jos n sus: sc pornctc dc
la cclc mai mici subcazuri. Combinnd solu iilc lor, sc ob in solu ii pcntru
subcazuri din ce n ce mai mari, pn se ajunge la solu ia cazului ini ial;
principiul optimalit ii: ntr-o sccvcn optim de decizii, fiecare
subsccvcn trebuie s fie de asemenea optim.
Ca i n cazul algoritmiilor grccdy, solu ia optim nu este neaprat unic.
Modelul general al metodei programrii dinamice
Dezvoltarea unui algoritm de programare dinamic poate fi descris de
urmtoarca succcsiunc dc pai:
se caracterizeaz structura unei solu ii optimc
sc dcIinctc rccursiv valoarca unci solu ii optimc
se calculeaz de jos n sus valoarea unei solu ii optimc.
171
Dac pe lng valoarea unei solu ii optimc sc dorctc i solu ia propriu-
zis, atunci se mai efectueaz urmtorul pas:
din inIorma iilc calculatc sc construictc dc sus n jos o solu ic
optim.
Acest pas se rezolv n mod natural printr-un algoritm recursiv, care
efectueaz o parcurgere n sens invers a secven ci optimc dc dccizii calculatc
anterior prin algoritmul de programare dinamic.
Exemplu
Considerm problema nmul irii matricclor:
Se consider matricele A
1
,A
2
,,A
n
, cu dimensiunile specificate. Pentru
a calcula produsul accstor matricc sunt ncccsarc n-1 nmul iri. Ordinca
efecturii produselor nu este unic determinat, datorit propriet ii dc
asociativitate. Dac m,atricele au dimensiuni diferite, numrul opera iilor dc
nmul irc clcmcntar pentru a ob inc matricca rczultat dcpindc dc ordinca dc
nmul irc alcas. Se cere s se gseasc modalitatea optim de asociere astfel
nct numrul nmul irilor s fie minim.
Rezolvare:
Considerm urmtorul exemplu:
AxBxCxD
unde A(13,5), B(5,89), C(89,3), D(3,34). Modalit ilc dc asocicrc sunt:
(((AB)C)D) 10582 nmul iri
((AB)(CD)) 54201 nmul iri
((A(BC))D) 2856 nmul iri
(A((BC)D)) 4055 nmul iri
(A(B(CD))) 26418 nmul iri
Este clar acum c este esen ial modul dc asocicrc a nmul irilor.
172
Modalitatea optim de asociere se poate determina fr a calcula toate
posibilit ilc. Notm cu C
i,j
numrul minim de nmul iri clcmcntarc ncccsarc
calculrii produsului A
i
,A
i+1
,, A
j
, pentru 1 i j n. Avem:
C
i,i
= 0
C
i,i+1
= d
i
d
i+1
d
i+2
C
i,j
este valoarea minim cutat
este verificat principiul optimalit ii i
C
i,j
= min { C
i,j
+ C
i,j
+ d
i
d
k+1
d
j+1
| 1kj}.
Sc va rc inc la Iiccarc pas indicc carc rcalizcaz minimul MinNrMul,
adic modul de asociere al matricelor. Aceast valoare ne permite construirea
arborelui binar care descrie ordinea efecturii opera iilor. VrIurilc arborclui
vor con inc limitclc subirului dc matricc cc sc asociaz, rdcina va con inc
(1,n), iar un subraborc cu rdcina (i,j) va avca ca dcsccndcn|i pc (i,k) i
(k+1,j), unde k este valoarea pentru care se realizeaz optimul cerut.
Parcurgerea arborelui n postordine indic ordinea efecturii produselor.
program OrdineInmultireMatrici;
const
MaxMatrici = 100;
type
PNod = ^TNod;
TNod = record
ValSt, ValDr: Integer;
ArbSt, ArbDr: PNod;
end;
173
var
Nr: Integer; { Numarul matricilor }
Dim: array[1 .. MaxMatrici + 1] of Integer; { Dimensiunile matricilor }
NrMul: array[1 .. MaxMatrici + 1, 1 .. MaxMatrici + 1] of Integer;
{ Nr. inmultirilor elementare necesare calcularii prod. Ai x ... x Aj }
{ Citirea datelor }
procedure Citeste;
var
I: Integer;
begin
repeat
Write(Numarul matricilor: );
Readln(Nr);
until (Nr > 0) and (Nr <= MaxMatrici);
Writeln(Sirul dimensiunilor:);
for I := 1 to Nr + 1 do
repeat
Write(Dimensiunea , I, : );
Readln(Dim[I]);
until Dim[I] > 0;
end;
{ Calculul numarului inmultirilor }
function CalcNrMul(I, J, K: Integer): Integer; { I <= K <= J }
begin
CalcNrMul := NrMul[I, K] + NrMul[K + 1, J] +
Dim[I] * Dim[K + 1] * Dim[J + 1];
end;
174
{ Minimizarea numarului inmultirilor }
function MinNrMul(I, J: Integer; var KMin: Integer): Integer;
var
K: Integer;
begin
KMin := I;
for K := I + 1 to J - 1 do
if CalcNrMul(I, J, K) < CalcNrMul(I, J, KMin) then KMin := K;
MinNrMul := CalcNrMul(I, J, KMin);
end;
{ Construirea arborelui }
function ConsArb(St, Dr: Integer): PNod;
var
Arbore: PNod;
begin
New(Arbore);
with Arbore^ do
begin
ValSt := St;
ValDr := Dr;
if St < Dr then
begin
ArbSt := ConsArb(St, NrMul[Dr, St]);
ArbDr := ConsArb(NrMul[Dr, St] + 1, Dr);
end
else
begin
ArbSt := nil;
ArbDr := nil;
175
end;
end;
ConsArb := Arbore;
end;
{ Parcurgerea in postordine a arborelui }
procedure PostOrdine(Arbore: PNod);
begin
if Arbore <> nil then
with Arbore^ do
begin
PostOrdine(ArbSt);
PostOrdine(ArbDr);
Write((, ValSt, ,, ValDr, ););
end;
end;
{ Rezolvarea problemei }
procedure Rezolva;
var
Arbore: PNod;
I, J, K, L: Integer;
begin
for I := 1 to Nr do
NrMul[I, I] := 0;
for L := 1 to Nr - 1 do
for I := 1 to Nr - L do
begin
J := I + L;
NrMul[I, J] := MinNrMul(I, J, K);
176
NrMul[J, I] := K; { Se memoreaza indicele minimului }
end;
Arbore := ConsArb(1, Nr);
Writeln(Sirul asocierilor:);
PostOrdine(Arbore);
Writeln;
end;
{ Programul principal }
begin
Citeste;
Rezolva;
end.
15.5. Metode euristice
n situa iilc n carc pcntru anumitc problcmc complcxc, pcntru a cror
rczolvarc nu sc cunosc algoritmi, sau acctia sunt incIicicn i (rclativ la timp,
spa iu) sc prcIcr utilizrea unor algoritmi care rezolv problema dat mult mai
rapid, cu efort mic, ns nu ne va furniza ntotdeauna cea mai bun solu ic, ci
doar solu ii acccptabilc, adic solu ii corcctc carc pot Ii cvcntual mbunt itc.
Prin algoritm euristic vom n clcgc un algoritm carc Iurnizcaz solu ii
bunc, nu ncaprat optimalc, carc poatc Ii implcmcntat i Iurnizcaz rczultatc
n timp util.
O idee frecvent utilizat const n descompunerea procesului de
dctcrminarc a solu ici n mai multc subproccsc succcsivc, Iiccarc Iiind optimal.
Optimul global nu va fi neaprat ob inut prin dctcrminri succesive de optimuri
localc (dc cxcmplu, n cazul mctodci Grccdy, solu ia trcbuia s fie acceptabil).
n practic, se caut de multe ori solu ii aproximativc.
177
Exemplu
Considerm problema (Problema comis-voiajorului):
Fiind date NrOrase localit i i cunoscndu-sc distan clc dintrc clc sc
cere s se determine traseul de lungime minim pe care trebuie s-l parcurg
comis-voiajorul pentru a vizita toate localit ilc, trccnd o singur dat printr-o
localitate, iar apoi s se rentoarc n localitatea de unde a plecat.
Rezolvare: se realizeaz aplicnd urmtoarea strategie - se alege
ntotdeauna cea mai apropiat localitate, dintre cele nevizitate. Pentru c un
traseu este un circuit nchis, putem considera ca punct de plecare oricare dintre
localit i. Pcntru Iiccarc localitatc considcrat ca localitate de plecare, se
dctcrmin trascc i sc rc inc trascul dc lungimc minim (procedura
GasesteItinerar). Alegnd toate localit i ca punct dc plccarc sc compar
lungimilc trascclor i sc rc inc minimul (proccdura Rezolva).
program ComisVoiajor;
const
MaxOrase = 100;
type
TOras = 1 .. MaxOrase;
TItinerar = array[1 .. MaxOrase] of TOras;
var
{ Date }
NrOrase: Integer;
Dist: array[1 .. MaxOrase, 1 .. MaxOrase] of Integer;
178
{ Rezultate }
Itinerar: TItinerar;
Lung: Integer;
{ Citirea datelor }
procedure Citeste;
var
I, J: Integer;
begin
repeat
Write(Numarul oraselor: );
Readln(NrOrase);
until (NrOrase > 0) and (NrOrase <= MaxOrase);
for I := 1 to NrOrase do
begin
Dist[I, I] := 0;
for J := I + 1 to NrOrase do
begin
repeat
Write(Distanta dintre orasul , I, si orasul , J, : );
Readln(Dist[I, J]);
until Dist[I, J] > 0;
Dist[J, I] := Dist[I, J];
end;
end;
end;
{ Gasirea unui itinerar minim, pornind din orasul de pornire dat }
procedure GasesteItinerar(OrasStart: Integer;
var Itinerar: TItinerar; var Lung: Integer);
179
var
Vizitat: packed array[1 .. MaxOrase] of Boolean;
DistMin: Integer;
OrasCurent, I, J: TOras;
begin
for I := 1 to NrOrase do
Vizitat[I] := False;
Vizitat[OrasStart] := True;
Lung := 0;
Itinerar[1] := OrasStart;
OrasCurent := OrasStart;
for I := 2 to NrOrase do
begin
DistMin := 0;
for J := 1 to NrOrase do
if not Vizitat[J] and
((DistMin = 0) or (DistMin > Dist[OrasCurent, J])) then
begin
DistMin := Dist[OrasCurent, J];
Itinerar[I] := J;
end;
Lung := Lung + DistMin;
OrasCurent := Itinerar[I];
Vizitat[OrasCurent] := True;
end;
end;
180
{ Rezolvarea problemei }
procedure Rezolva;
var
ItinerarTmp: TItinerar;
LungTmp: Integer;
I: TOras;
begin
GasesteItinerar(1, Itinerar, Lung);
for I := 2 to NrOrase do
begin
GasesteItinerar(2, ItinerarTmp, LungTmp);
if LungTmp < Lung then
begin
Itinerar := ItinerarTmp;
Lung := LungTmp;
end;
end;
end;
{ Afisarea rezultatelor }
procedure Afis;
var
I: Integer;
begin
Write(Traseul gasit: );
for I := 1 to NrOrase do
Write(Itinerar[I] : 4);
Writeln;
Writeln(Lungimea drumului: , Lung);
end;
181
{ Programul principal }
begin
Citeste;
Rezolva;
Afis;
end.