atestat divide et impera
TRANSCRIPT
5/13/2014
DIVIDE ET IMPERA
Metode de programare
MURARU STEFAN, CLASA A XII-A RAINDRUMATOR : PROF. ACHIREI MARIANCOLEGIUL NATIONAL „STEFAN CEL MARE” TARGU-NEAMT
DIVIDE ET IMPERA
Metode de programare
MURARU STEFAN, CLASA A XII-A RAINDRUMATOR : PROF. ACHIREI MARIANCOLEGIUL NATIONAL „STEFAN CEL MARE” TARGU-NEAMT
CuprinsIntroducere......................................................................................................................................................2
Aplicații...........................................................................................................................................................5
Căutare binară.............................................................................................................................................5
Turnurile din Hanoi.....................................................................................................................................7
Sortare Rapida (QuickSort).........................................................................................................................9
Sortare prin interclasare (MergeSort)........................................................................................................11
Sortare prin inserție binara........................................................................................................................13
Concluzii.......................................................................................................................................................14
Bibliografie...................................................................................................................................................15
1
Introducere
În politică și sociologie, „Divide et impera” este o combinație de tactici (politice,
militare sau economice) de câștigare și menținere a puterii prin divizarea unei populații
în entități mai mici care luate separat au putere mai mică decât cel care își impune
voința. Este deseori întâlnită ca o strategie în care grupuri de putere mică sunt
împiedicate să se unească și să devină mai puternice.
Divide et impera se bazează pe principiul descompunerii problemei în două sau
mai multe subprobleme (mai ușoare), care se rezolvă, iar soluția pentru problema
inițială se obține combinând soluțiile subproblemelor. De multe ori, subproblemele
sunt de același tip și pentru fiecare din ele se poate aplica aceeași tactică a
descompunerii în (alte) subprobleme, până când (în urma descompunerilor repetate) se
ajunge la probleme care admit rezolvare imediată.
Metoda DIVIDE ET IMPERA se poate aplica in rezolvarea unei probleme care
îndeplinește următoarele condiții :
se poate descompune in ( doua sau mai multe) subprobleme ;
aceste subprobleme sunt independente una fata de alta (o subproblema nu
se rezolva pe baza alteia si nu se folosește rezultate celeilalte);
aceste subprobleme sunt similare cu problema inițială;
la rândul lor subproblemele se pot descompune (daca este necesar) in alte
subprobleme mai simple;
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 rara. După cum sugerează si numele "desparte si stăpânește "etapele
rezolvării unei probleme (numita problema inițială) in DIVIDE ET IMPERA sunt :
2
descompunerea problemei inițiale in subprobleme independente ,similare
problemei de baza ,de dimensiuni mai mici ;
descompunerea treptata a subproblemelor in alte subprobleme din ce in ce
mai simple ,pana când se pot rezolva imediata ,prin algoritmul simplificat ;
rezolvarea subproblemelor simple ;
combinarea soluțiilor găsite pentru construirea soluțiilor subproblemelor de
dimensiuni din ce in ce mai mari ;
combinarea ultimelor soluții determina obținerea soluției problemei inițiale
Metoda DIVIDE ET IMPERA admite o implementare recursiva ,deoarece
subproblemele sunt similare problemei inițiale, dar de dimensiuni mai mici .
Principiul fundamental al recursivității este autoapelarea unui subprogram când
acesta este activ; ceea ce se întâmplă la un nivel ,se întâmplă la orice nivel ,având grija
sa asiguram condiția de terminare ale apelurilor repetate .Asemănător se întâmplă si in
cazul metodei DIVITE ET IMPERA ; la un anumit nivel sunt doua posibilități :
s-a ajuns la o (sub)problema simpla ce admite o rezolvare imediata caz in
care se rezolva (sub)problema si se revine din apel (la subproblema
anterioara, de dimensiuni mai mari);
s-a ajuns la o (sub)problema care nu admite o rezolvare imediata ,caz in
care o descompunem in doua sau mai multe subprobleme si pentru fiecare
din ele se continua apelurile recursive(ale procedurii sau funcției).
In etapa finala a metodei DIVIDE ET IMPERA se produce combinarea
subproblemelor (rezolvate deja) prin secvențele de revenire din apelurile recursive.
Etapele metodei DIVIDE ET IMPERA (prezentate anterior)se pot reprezenta prin
următorul subprogram general (procedura sau funcție )recursiv exprimat in limbaj
natural:
Subprogram DIVIMP (PROB);Daca PROBLEMA PROB este simpla
3
Atunci se rezolva si se obține soluția SOLAltfel pentru i=1,k
executa DIVIMP(PROB) si se obține SOL1;Se combina soluțiile SOL 1,... ,SOL K si se obține SOL;
Sfârșit _subprogram;
De obicei problema inițială se descompune in doua subprobleme mai simple. In
acest caz etapele generale ale metodei DIVIDE ET IMPERA se pot reprezenta concret,
în limbaj pseudocod ,printr-o procedura recursiva astfel :
Procedura DIVIMP(li,ls,sol);Daca ((ls-li)<=eps)
Atunci REZOLVA (li,ls,sol);Altfel
DIVIDE (li,m,ls);DIVIMP(li,msol1);DIVIMP(m,ls,sol2);
COMBINA(sol1,sol2,sol)Sfârșit_ procedura;
Procedura DIVIMP se apelează pentru problema inițială care are dimensiunea intre
limita inferioara (li) si limita inferioara(ls);daca (sub)problema este simpla (ls-
li<=eps),atunci procedura REZOLVA ii afla soluția imediat si se produce întoarcerea
din apelul recursiv; dacă (sub)problema este (încă) complexa ,atunci procedura
DIVIDE o împarte in doua subprobleme ,alegând poziția m intre limitele li si
ls ;pentru fiecare din cele doua subprobleme se reapelează recursiv procedura
DIVIMP; in final ,la întoarcerile din apeluri se produce combinarea celor doua soluții
sol1 si sol2 prin apelul procedurii COMBINA.
4
Aplicații
Căutare binară
Se citește un vector cu n componente numere întregi (numerele se presupun
ordonate crescător) și o valoare întreagă ("nr"). Să se decidă dacă nr se găsește sau nu
printre numerele citite, iar în caz afirmativ să se tipărească indicele componentei care
conține această valoare.
O rezolvare în care nr se compară pe rând cu toate cele n componente reprezintă o
pierdere de performanță (nu exploatează faptul că cele n valori sunt în secvență
crescătoare). Algoritmul care va fi propus este optim și se poate spune că face parte
dintre algoritmii "clasici".
Funcția care va fi implementată va decide dacă valoarea căutată se găsește printre
numerele aflate pe poziții de indice cuprins între i și j (inițial, i=1, j=n). Pentru aceasta,
se va proceda astfel:
dacă nr coincide cu valoarea de la mijloc, aflată pe poziția de indice (i+j)/2, se
tipărește indicele și se revine din apel (problema a fost rezolvată).
în caz contrar, dacă mai sunt și alte elemente de analizat (adică i<j, deci nu au
fost verificate toate pozițiile necesare), problema se descompune astfel:
dacă nr este mai mic decât valoarea testată (din mijloc), înseamnă că nu se
poate afla pe pozițiile din partea dreaptă, întrucât acestea sunt cel puțin mai
mari decât valoarea testată. Nr se poate găsi doar printre componentele cu
indice între i și (i+j)/2 - 1, caz în care se reapelează funcția cu acești
parametri;
dacă nr este mai mare decât valoarea testată (din mijloc), înseamnă că nu se
poate afla în stânga; se poate găsi doar printre componentele cu indicele între
(i+j)/2 + 1 și j, caz în care se reapelează funcția cu acești parametri.
5
dacă nu mai sunt alte elemente de analizat (pentru că i=j și valoarea din
mijloc, v[i], nu coincide cu nr), se concluzionează că nr nu apare în cadrul
vectorului.
Această problemă nu mai necesită analiza tuturor subproblemelor în care se
descompune, ea se reduce la o singură subproblemă, iar partea de combinare a
soluțiilor dispare. În linii mari, această rezolvare este tot de tip "divide et impera".
#include <iostream> using namespace std; int v[100], n, nr; void caut(int i, int j) { int m = (i+j)/2; if (nr==v[m]) cout<<"găsit, indice="<<m; else if (i<j) if (nr<v[m]) caut(i, m-1); else caut(m+1, j); else cout<<"nu a fost găsit."; } int main( ) { cout<<"n="; cin>>n; for (int i=1; i<=n; i++) { cout<<"v["<<i<<"]="; cin>>v[i]; } cout<<"nr="; cin>>nr; caut (0,n); return 0; }
6
Turnurile din Hanoi
Se dau 3 tije simbolizate prin a,b,c. Pe tija a se găsesc n discuri de diametre
diferite, așezate in ordine descrescătoare a diametrelor. Se cere sa se mute de pe tija a
pe b, utilizând ca tija intermediara tija c, toate cele n discuri, respectând următoarele
reguli:
la fiecare pas se muta un singur disc ;
nu este permis sa se așeze un disc cu diametrul mai mare peste un disc cu
diametrul mai mic.
Rezolvare:
Daca n=1 se face mutarea ab, adică se muta discul de pe tija a pe tija b.
Daca n=2 se fac mutările ac,ab,cb.
Daca n>2 . Notam cu H(n,a,b,c) șirul mutărilor celor n discuri de pe tija a pe
tija b , utilizând ca tija intermediara, tija c.
Conform strategiei Divide et impera încercăm sa descompunem problema in alte
doua subprobleme de același tip, urmând apoi combinarea soluțiilor. Deci: mutarea
celor n discuri de pe tija a pe tija b, utilizând ca tijă intermediara tija c, este echivalenta
cu:
mutarea a n-1 discuri de pe tija a pe tija c , utilizând ca tijă intermediară tija b;
mutarea discului rămas de pe tija a pe tija b;
mutarea a n-1 discuri de pe tija c pe tija b , utilizând ca tijă intermediară tija a.
#include <iostream>using namespace std;
char a, b, c;int n;
void han(int n, char a, char b, char c){
7
if (n == 1) cout << a << b << endl;else{
han(n - 1, a, c, b);cout << a << b << endl;han(n - 1, c, b, a);
}}
int main(void){
cout << "n = "; cin >> n;a = 'a'; b = 'b'; c = 'c';han(n, a, b, c);return 0;
}
8
Sortare Rapida (QuickSort)
Un tablou V se completează cu n elemente numere reale .Să se ordoneze crescător
folosind metoda de sortare rapida .
Soluția problemei se bazează pe următoarele etape implementate in
programul principal:
se apelează procedura “quick” cu limita inferioara li=1 si limita superioara
ls=n;
functia”poz” realizează mutarea elementului v[i] exact pe
poziția ce o va ocupa acesta in vectorul final ordonat ; functia”poz”
întoarce (in k ) poziția ocupata de acest element;
in acest fel ,vectorul V se împarte in doua părți : li …k-1 si k+1…ls;
pentru fiecare din aceste părți se reapelează procedura “quick”, cu limitele
modificate corespunzător ;
in acest fel ,primul element din fiecare parte va fi poziționat exact pe poziția
finala ce o va ocupa in vectorul final ordonat (functia“poz”);
fiecare din cele doua părți va fi ,astfel ,împărțită in alte doua părți ;procesul
continua pana când limitele părților ajung sa se suprapună ,ceea ce indica ca
toate elementele vectorului au fost mutate exact pe pozițiile ce le vor ocupa
in vectorul final ;deci vectorul este ordonat ;
in acest moment se produc întoarcerile din apelurile recursive si programul
își termina execuția .
#include<iostream.h>int v[100],n,k;
void poz(int li,int ls,int & k,int v[100]){
9
int i=li,j=ls,c,i1=0,j1=-1;while(i<j){
if(v[i]>v[j]){c=v[j];v[j]=v[i];v[i]=c;c=i1;i1=-j1;j1=-c;}
i=i+i1;j=j+j1;
}k=i;
}
void quick(int li,int ls){
if(li<ls){
poz(li,ls,k,v);quick(li,k-1);quick(k+1,ls);
}}void main(){
int i;cout<<"n=";cin>>n;for(i=1;i<=n;i++){
cout<<"v["<<i<<"]=";cin>>v[i];
}quick(1,n);for(i=1;i<=n;i++) cout<<v[i]<<" ";
}
10
Sortare prin interclasare (MergeSort)
Tabloul unidimensional V se completează cu n numere reale. Sa se ordoneze
crescător folosind sortare prin interclasare.
Sortarea prin interclasare se bazează pe următoarea logica : vectorul V se
împarte ,prin înjumătățiri succesive ,in vectori din ce in ce mai mici ;când se ating
vectorii de maxim doua elemente ,fiecare dintre aceștia se ordonează printr-o simpla
comparare a elementelor ;cate doi astfel de mini- vectori ordonați se interclasează
succesiv pana se ajunge iar la vectorul V.
#include <iostream>using namespace std;int a[1000],n; void interclas(int i,int m,int j){
int b[1000];int x=i;int k=1;int y=m+1;while(x<=m && y<=j)
if (a[x]<a[y]) b[k++]=a[x++]; else b[k++]=a[y++]; while (x<=m) b[k++]=a[x++]; while (y<=j) b[k++]=a[y++]; int t=i; for (k=1;k<=(j-i)+1;k++) a[t++]=b[k];} void divimp(int i,int j)
11
{if (i<j)
{int m=(i+j)/2;
divimp(i,m); divimp(m+1,j); interclas(i,m,j);
}} void main(){
clrscr();cout<<"n=";cin>>n;for(int i=1;i<=n;i++)
{cout<<"a["<<i<<"]=";
cin>>a[i]; }
divimp(1,n);for(i=1;i<=n;i++)
cout<<a[i]<<' ';}
OBSERVATII o mecanismul general de tip Divide et Impera se găsește implementat in
procedura “divimp” ;o astfel de abordare a problemei sortării unii vector conduce la economie de timp
de calcul ,deoarece operația de interclasare a doi vectori deja ordonați este foarte rapida ,iar ordonarea independenta celor doua jumătăți(mini- vectori) consuma in total aproximativ a doua parte din timpul care ar fi necesar ordonării vectorului luat ca întreg .
12
Sortare prin inserție binara
Sa se ordoneze crescător un tablou unidimensional V de n numere reale ,folosind sortarea prin inserție binara .
Pentru fiecare element v[i] se procedează in patru pași:
se considera ordonate elementele v[1],v[2],….,v[i-1]; se caută poziția k pe care urmează s-o ocupe v[i] intre elementele v[1],v[2],
…,v[i-1](procedura “poz” prin căutare binara); se deplasează spre dreapta elementele din pozițiile k,k+1,…,n(procedura
“deplasare”); inserează elementul v[i] in poziția k (procedura „deplasare”);
Se obține o succesiune de k+1 elemente ordonate crescător.
#include<iostream.h>void main ( ){ int i,j,n,aux,a[50]; cout<<" introduceți dimensiunea șirului: "<<endl;cin>>n; cout<<"Dați elementele șirului:"<<endl; for(i=0;i<n;i++) { cout<<"a["<<i<<"]=";cin>>a[i]; } for(j=1;j<n;j++) { aux=a[j]; i=j-1; while (aux<a[i] && i>=0) { a[i+1]=a[i]; i=i-1; } a[i+1]=aux; } cout <<"Sirul ordonat este:"; for(i=0;i<n;i++) cout<<a[i]<<" "; cout<<endl;}
13
Concluzii(analiza a complexității timp pentru algoritmii Divide et Impera)
Algoritmii de tip Divide et Impera au buna comportare in timp ,daca se îndeplinesc următoarele condiții:
dimensiunile subprogramelor(in care se împarte problema inițială) sunt aproximativ egale(“principiul balansării”);
lipsesc fazele de combinare a soluțiilor subproblemelor (căutare binara).
14
Bibliografie
Livia Toca, Cristian Opincaru, AdrianSindile , MANUAL DE INFORMATICA PENTRU CLS.a-X a, Editura Niculescu ;
Radu Visinescu, BAZELE PROGRAMARII , Editura Petrion ;
Cristian Udrea, TEORIE SI APLICATII, Editura Arves ;
Kris Jamsa, Lars Klander, TOTUL DESPRE C si C++, Editura Teora
Webografie
www.scribd.com
www.infoarena.com
15