Sunteți pe pagina 1din 3

Pentru un nou nscut orice problem e nou

SUM

MAXIM

Clara Ionescu

focus

Secvena de

Frumuseea problemelor de programare se ascunde n rezolvarea lor. O


problem care se rezolv n multe linii surs, cu un algoritm banal, nu prea
are anse s se remarce n rndul rezolvitorilor de probleme de algoritmic.
Rsfoind notie fcute "de demult" am (re)descoperit o problem a crui enun
este ct se poate de simplu, rezolvarea n schimb este foarte frumoas.

Enun

Se consider un ir de n numere ntregi, printre care exist


cel puin un element pozitiv. Scriei un program care determin secvena avnd suma elementelor maxim.
Exemplu

Complexitatea acestui algoritm, format din trei cicluri


imbricate este O(n3). Pentru n = 1000 un calculator cu performane medii va lucra aproape o or. Aceast complexitate nu poate fi acceptat, de aceea vom cuta modaliti de
micorare a complexitii, astfel nct s avem mai nti un
algoritm ptratic, apoi unul liniar.

n=10

irul: 1 2 6 3 4 5 2 10 5 6
Rezultate:
Suma maxim: 20
Lungimea secvenei: 5
Poziia de nceput a secvenei: 4
Poziia de sfrit a secvenei: 8
Secvena avnd suma 20: 3 4 5 2 10

Varianta II

Varianta I

}
}
}

Cutnd optimizri posibile, observm c suma secvenei


T[st..dr] poate fi determinat n funcie de suma calculat anterior, pentru secvena T[st..dr-1]. Evident, orice sum T[st..dr] poate fi comparat cu suma maxim
obinut pn n acel moment, imediat dup ce a fost calculat. Rezult un nucleu de complexitate O(n2), deoarece
n algoritm vom avea doar dou cicluri imbricate:
Suma_Max:=T[1];
for st:=1 to n do
begin
sum:=0;
for dr:=st to n do
begin
sum:=sum+T[dr];
if Suma_Max<sum then Suma_Max:=sum
end
end;

Ginfo nr. 2 - februarie 2001

Cea mai simpl idee care conduce la o rezolvare a


acestei probleme ar fi de a genera toate perechile de numere ntregi st i dr avnd proprietatea: 1 st dr n, calculnd pentru fiecare pereche suma elementelor secvenei
T[st..dr] i determinnd secvena avnd suma maxim.
n acest caz algoritmul ar avea urmtorul nucleu:
Suma_Max:=T[1];
{ Suma_Max: suma maxima cautata
for st:=1 to n do
{ st: pozitia de inceput a secventei
for dr:=st to n do
{ dr: pozitia de sfarsit a secventei
begin
sum:=0;
{ sum: suma secventei actuale

for i:=st to dr do
sum:=sum+T[I];
if Suma_Max<sum
then Suma_Max:=sum
end;

21

focus

Varianta III

Al doilea algoritm ptratic are la baz o idee nou, dar care


folosete spaiu suplimentar, dublnd necesarul de memorie. n rezolvarea pe care o propunem n aceast variant,
presupunem c dimensiunea irului nu va fi aa de mare
nct acest inconvenient s fac imposibil obinerea soluiei pe aceast cale.
Vom nota cu Sum_Part[i] suma elementelor secvenei T[1..i]. Vom calcula aceste sume pariale pentru valorile i=0,1,,n la nceputul algoritmului i le vom memora n tabloul SumPart[0..n]. n consecin, suma elementelor unei secvene T[st..dr] se calculeaz simplu,
folosind elementele acestui tablou auxiliar:
T[st..dr]=Sum_Part[dr]-Sum_Part[st-1].

Programul n care s-a implementat algoritmul care


are la baz ideea prezentat, este urmtorul:

Ginfo nr. 2 - februarie 2001

Listing VAR3.PAS

22

Program Secventa_de_suma_maxima;
const n=100;
var T:array[1..n] of Integer; { sirul dat
Sum_Part:array[0..n] of Integer;
{ sirul sumelor partiale
inceput,sfarsit,st,dr,i:Byte;
Suma_Max,sum:Integer;
Begin
Writeln('Sirul dat: ');
Sum_Part[0]:=0;
{ este nevoie de Sum_Part[i-1] cand i=1
for i:=1 to n do
{ in paralel cu citirea sirului
{ se calculeaza sumele partiale
begin
Read(T[i]);
Sum_Part[i]:=Sum_Part[i-1]+T[i]
end;
Writeln;
Suma_Max:=T[1];
{ initializarea sumei maxime cautate
for st:=1 to n do
for dr:=st to n do
begin
sum:=Sum_Part[dr]-Sum_Part[st-1];
{ sume curente
if Suma_Max<sum then
begin
Suma_Max:=sum;
{ suma maxima curenta
inceput:=st;
{ pozitia de inceput a secventei
sfarsit:=dr
{ pozitia de sfarsit a secventei
end
end;
Writeln('Secventa avand suma maxima: ');

}
}

}
}
}

}
}
}

for i:=inceput to sfarsit do


Write(T[i],' ');
Writeln
End.

Evident, exist i alte posibiliti de a rezolva aceast


problem n complexitate ptratic; propunem cititorilor
s caute un algoritm recursiv, folosind observaiile prezentate.

Varianta IV

n continuare urmeaz descrierea unui algoritm avnd


complexitatea O(n). Aceast performan se obine datorit faptului c tabloul se parcurge o singur dat.
n paralel cu parcurgerea irului de la stnga la dreapta
vom determina i memora la fiecare pas suma maxim posibil, n variabila Suma_Max. S presupunem c am aflat
suma maxim i secvena T[1..i-1] respectiv. Se pune
problema extinderii metodei pentru calcularea sumei maxime pentru T[1..i].
Se observ c dup parcurgerea primelor i elemente
ale irului, suma maxim este egal cu suma maxim a primelor i-1 elemente (Suma_Max) sau este mai mare dect
aceasta. Dac este mai mare, nseamn c din aceast sum
maxim face parte i elementul de pe poziia i, deci avem
un subir care are elementul de sfrit cel de-al i-lea element din irul dat (aceast sum o vom numi Suma_C).
Suma Suma_C nu va fi calculat de fiecare dat de la
nceput, ci vor fi aplicate raionamentele deja cunoscute:
se va utiliza suma maxim a secvenei ce se termin pe poziia i-1. n consecin obinem:
Suma_Max:=T[1];
Suma_C:=Suma_Max;
for i:=1 to n do
begin
Suma_C:=max(Suma_C+T[i],0];
Suma_Max:=max(Suma_Max,Suma_C)
end;

{1}
{2}

La examinarea acestei secvene o deosebit atenie merit acordat variabilei Suma_C. nainte de a fi executat
instruciunea de atribuire {1} din corpul ciclului, valoarea
acestei variabile este egal cu suma maxim a elementelor
secvenei care se termin n poziia i-1. n urma execuiei
acestei instruciuni de atribuire n Suma_C va fi depus suma maxim a elementelor secvenei care se termin n poziia i i ncepe ntr-o poziie memorat n momentul nceperii nsumrii elementelor secvenei ncepnd cu poziia poz_inceput. Evident, la primul pas aceast variabil
are valoarea 1, indicele primului element din ir.
Este momentul s ne aducem aminte c irul dat conine cel puin un element de valoare pozitiv, (proprietate
neexploatat n nici una din variantele de rezolvare prezentate). Din aceast particularitate rezult c dac irul ar
avea n-1 elemente negative i unul singur pozitiv, secven-

Listing VAR4.PAS

}
}
}
}
}
}
}

}
}
}
}
}
}
}
}

}
}
}
}

n urma executrii programului pentru irul T=(4,2,


-7,9,-10,3,10,-3,5,-15), rezultatele furnizate de
program sunt:

Suma maxima: 15
Lungimea secventei: 4
Incepe din pozitia: 6
Sfarsitul in pozitia: 9
Secventa avand suma maxima: 3 10 3 5
n urma executrii programului pentru irul T=(1,2,3,
-1,-2,-3,6,7,-7,8), rezultatele furnizate sunt:
Suma maxima: 14
Lungimea secventei: 10
Incepe din pozitia: 1
Sfarsitul in pozitia: 10
Secventa avand suma maxima: 1 2 3 -1 -2 -3 6
7 -7 8

Se observ c secvena obinut ca rezultat are lungimea maxim printre secvenele care au aceeai sum maxim. n acest exemplu secvena 6 7 -7 8 are, de asemenea,
suma 14. Lsm pe seama cititorului s caute o soluie care
s furnizeze ca rezultat secvena de lungime minim i
avnd suma maxim. De asemenea, se poate pune ntrebarea: cum procedm dac ne intereseaz prima secven
avnd proprietatea cerut, ultima sau eventual, toate secvenele.

Bibliografie:

Gh. Bostan, I. Mocanu, Al VII-lea concurs republican de


informatic, Chiinu, 1993, nepublicat
D-na lect. univ. Clara Ionescu este redactor-ef al GInfo. Poate fi contactat prin e-mail la adresa clara@cs.ubbcluj.ro.

Ginfo nr. 2 - februarie 2001

Program Secventa_de_suma_maxima;
const n=100;
var T:array[1..n] of Integer; { sirul dat
Suma_Max,
{ suma maxima cautata
Suma_C:Integer;
{ suma maxima curenta
inceput,
{ pozitia de inceput a secventei
sfarsit,
{ pozitia de sfarsit a secventei
poz_inceput,
{ pozitia de inceput a
{
secventei curente
i:Byte;
Begin
Writeln('Sirul dat: ');
for i:=1 to n do Read(T[i]);
Writeln;
{ initializarea sumei maxime
Suma_Max:=T[1];
{ initializarea sumei curente
Suma_C:=Suma_Max;
{ initializarea pozitiei de inceput
{
a secventei curente
poz_inceput:=1;
{ initializarea pozitiei de inceput
{
a secventei de suma maxima
inceput:=1;
{ initializarea pozitiei de sfarsit
{
a secventei de suma maxima
sfarsit:=1;
for i:=2 to n do
begin
if Suma_C<0 then
{ daca Suma_C este negativa
begin
{ aceasta se reinitializeaza cu T[i]
Suma_C:=T[i];
{ noua secventa posibila incepe la
{
pozitia i
poz_inceput:=i
end
else

{ lui Suma_C i se adauga T[i] }


Suma_C:=Suma_C+T[i];
if Suma_Max<Suma_C then
{ se actualizeaza Suma_Max }
begin
Suma_Max:=Suma_C;
{ actualizarea pozitiei de inceput }
inceput:=poz_inceput;
{ actualizarea pozitiei de sfarsit }
sfarsit:=i
end
end;
Writeln('Suma maxima: ',Suma_Max);
Writeln('Lungimea secventei: ',
sfarsit-inceput+1);
Writeln('Incepe din pozitia: ',inceput);
Writeln('Sfarsitul in pozitia: ',sfarsit);
Writeln('Secventa avand suma maxima: ');
for i:=inceput to sfarsit do
Write(T[i],' ');
Writeln
End.

focus

a avnd suma maxim s-ar reduce la un singur element i


anume la acest numr pozitiv care ar da natere la o sum
pozitiv. Rezult c suma maxim cutat n orice situaie
va fi o sum pozitiv. n consecin, ct timp suma curent
este pozitiv, prin atribuirea {1}, lui Suma_C i se adaug
T[i]. Dac, la un moment dat se constat c Suma_C este
negativ, atunci acestei variabile i se atribuie valoarea elementului T[i].
n ambele cazuri variabila Suma_C va fi comparat cu
Suma_Max, actualiznd valoarea Suma_Max dup caz. n
continuare urmeaz varianta final a programului Pascal.

23

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