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 LH SRVLELO, 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 LH GH VHOHF LH care indic la orice moment care este cel mai promi tor dintrc candida ii nc nefolosi i o IXQF LH RELHFWLY 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 LLOH LQWHUQH} &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 LLOH GH FRQWLQXDUH 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) L n 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.