Sunteți pe pagina 1din 3

1.

Subşir crescător maximal


Fie un şir A=(a1, a2, ..., an). Numim subşir al şirului A o succesiune de elemente din A, în ordinea
în care acestea apar în A: ai1, ai2, ..., aik, unde 1i1<i2<...<ikn. Determinaţi un subşir
crescător al şirului A de lungime maximă.
Exemplu
Pentru A=(8,3,6,50,10,8,100,30,60,40,80) o soluţie poate fi:
( 3,6, 10, 30,60, 80).
Soluţie
1. Fie Ai =(ai ai  ...ai ) cel mai lung subşir crescător al lui şirului A. Observăm că el coincide
1 1 2 k
cu cel mai lung subşir crescător al şirului (ai1, ai1+1, ..., an). Evident Ai2=(ai2ai3 ...aik) este
cel mai lung subşir crescător al lui (ai , ai +1, ..., an), etc. Prin urmare, o subproblemă a problemei
2 2
iniţiale constă în determinarea celui mai lung subşir crescător care începe cu ai,i{1,.., n}.
Subproblemele nu sunt independente: pentru a determina cel mai lung subşir crescător care incepe
cu ai, este necesar să determinăm cele mai lungi subşiruri crescătoare care încep cu aj, aiaj,
j{i+1,.., n}. Notăm cu n numărul de elemente ale şirului a, iar cu m lungimea maximă a unui
subşir crescător al lui a.
2. Pentru a reţine soluţiile subproblemelor vom considera doi vectori suplimentari l şi poz, fiecare
cu câte n componente, având semnificaţia:
l[i]=lungimea celui mai lung subşir crescător care începe cu a[i];
poz[i]=poziţia elementului care urmează după a[i] în cel mai lung subşir crescător care
începe cu a[i], dacă un astfel de element există, sau 0 dacă un astfel de element nu există.
3. Relaţia de recurenţă care caracterizează substructura optimală a problemei este:
l[n]=1; poz[n]=0;
l[i]=max{1+l[j]|a[i]a[j]}
j=i+1,n
poz[i]= indicele j pentru care se obţine maximul l[i].
4. Rezolvăm relaţia de recurenţă în mod bottom-up:
int i, j;
for (i=n; i>0; i--)
{ l[i]=1;poz[i]=0;//valori iniţiale
for (j=i+1; j<=n; j++)
if (a[i] <= a[j] && l[i]<1+l[j])
//actualizăm lungimea si indicele elementului care urmează după a[i]
{l[i]=1+l[j]; poz[i]=j;}
if (m<l[i])
//actualizăm lungimea si indicele primului element
{m=l[i];prim=i;}

Pentru a determina soluţia optimă a problemei, memorăm în variabila m maximul din vectorul l ,
în timp ce variabila prim va reţine indicele primului element al celui mai lung subşir, apoi afişăm
soluţia, începând cu primul element şi utilizând informaţiile memorate în vectorul poz:
int i;
cout<<"Lungimea celui mai lung subsir crescator: " <<m;
cout<<"\nCel mai lung subsir:\n";
for (i=prim; i>0; i=poz[i])
cout<<a[i]<<' ';
Programul complet:
1. #include<fstream>
2. #include<iostream>
3. using namespace std;
4. #define MAX 100001
5. ifstream fin("sir.in");
6. int a[MAX],l[MAX],poz[MAX];
7. int n,m,prim;
8.
9. void citire()
10. {
11. int i;
12. fin>>n;
13. for(i=1;i<=n;i++)
14. fin>>a[i];
15. }
16.
17. void subsir()
18. {
19. int i,j;
20. for(i=n;i>=1;i--)
21. { l[i]=1;poz[i]=0;
22. for(j=i+1;j<=n;j++)
23. if(a[i]<a[j] && l[i]<1+l[j])
24. {l[i]=1+l[j];poz[i]=j;}
25. if(m<l[i]) {m=l[i];prim=i;}
26. }
27. }
28.
29. void tipar()
30. {
31. int i;
32. cout<<m<<endl;
33. for(i=prim;i>0;i=poz[i])
34. cout<<a[i]<<' ';
35. }
36. int main()
37. {
38. citire();
39. subsir();
40. tipar();
41. fin.close();
42. return 0;
43. }
Varianta optimizată
2. Folosim o stivă memorată sub forma unui vector b[i], cu i=1,…,n elementele având
următoarea semnificaţie:
b[i] = adresa primului element din şirul A pentru care subşirul care începe cu acel element are
lungimea i.

Din definiţia şirului b şi modul de construcţie rezultă că elementele a[b[1]], a[b[2]], … a[b[n]]
sunt sortate descrescător. Actualizarea vectorului b se face cu ajutorul algoritmului de căutare
binară a valorii a[i] în vectorul b. Algoritmul de căutare binară returnează un indice k pentru care
a[b[k]] <= a[i] <= a[b[k-1]]. Avem două situaţii posibile:
a) k=m+1 > m, aceasta înseamnă că se poate obţine un subşir de lungime mai mare, m+1,
b[k]=i
b) k<=m, actualizăm subşirul de lungime k cu indicele i, adică b[k]=i

1. #include<fstream> 30.
2. #include<iostream> 31. void subsir()
3. using namespace std; 32. {
4. #define MAX 100001 33. int i,j,k;
5. ifstream fin("sir.in"); 34. a[0]=1234567890;
6. int a[MAX],b[MAX],poz[MAX]; 35. for(i=n;i>=1;i--)
7. int n,m; 36. {
8. 37. poz[i]=0;
9. void citire() 38. k=caut(1,m,a[i]);
10. { 39. if(k>m)
11. int i; 40. {
12. fin>>n; 41. poz[i]=b[k-1];
13. for(i=1;i<=n;i++) 42. m=k;
14. fin>>a[i]; 43. b[k]=i;
15. } 44. }
16. 45. else
17. int caut(int p, int u, int x) 46. {
18. { 47. poz[i]=b[k-1];
19. int m; 48. if(a[b[k]]<a[i])
20. while(p<=u) 49. b[k]=i;
21. { 50. }
22. m=p+(u-p)/2; 51. }
23. if(x<a[b[m]]) 52. }
24. p=m+1; 53.
25. else 54. void tipar()
26. u=m-1; 55. {
27. } 56. int i;
28. return p; 57. cout<<m<<'\n';
29. } 58. for(i=b[m];i>0;i=poz[i])
59. {
60. cout<<a[i]<<' ';
61. }
62. }
63. int main()
64. {
65. citire();
66. subsir();
67. tipar();
68. fin.close();
69. return 0;
70. }

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