Documente Academic
Documente Profesional
Documente Cultură
PREZENTAREA METODEI
Metoda constă în descompunerea problemei de rezolvat în subprobleme. În urma descompunerii pot apărea două
situaţii:
- problemele obţinute sunt elementare (soluţiile acestor probleme se deduc direct);
- problemele obţinute sunt neelementare, ale căror soluţii nu sunt direct deductibile.
Procedeul de descompunere a problemei date în suprobleme continuă până în momentul în care toate
subproblemele obţinute sunt elementare (de unde rezidă caracterul recursiv al metodei).
În cadrul acestei metode se disting trei etape:
1. împăţirea problemei în două sau mai multe subprobleme;
2. rezolvarea subproblemelor obţinute, direct (în cazul problemelor elementare) sau prin reducerea acestora la
alte subprobleme (recursiv);
3. combinarea soluţiilor subproblemelor pentru obţinerea soluţiei problemei iniţiale.
2. Se citeşte un şir cu n elemente numere naturale. Să se determine cel mai mare divizor comun dintre elementele
şirului.
Rezolvare:
Funcţia divide calculeză cmmdc-ul elementelor unui subşir cu indicii s şi d. Realizăm o funcţie cmmdc care
calculează cmmdc-ul dintre două valori. Folosind metoda Divide et Impera împărţim problema dată în subprobleme,
care, pentru a deveni elementare trebuie să presupună calculul cmmdc-ului a două valori (cm1 şi cm2). Pentru un şir cu
n elemente, apelul extern va fi divide(1,n,cm).
Exemplu:
Pentru n=5 si a=(14,77,84,21,63) se va afişa valoarea 7.
#include<iostream>
#include<iomanip.h>
#include<fstream>
int a[30],n,cm;
void citire(int a[],int &n)
{
int i;
ifstream f("div2.txt");
f>>n;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
int cmmdc(int a,int b)
{
int r;
do
{
r=a%b;
a=b;
b=r;
}
while (r>0);
return a;
}
void divide(int s,int d,int &cm)
{
int m,cm1,cm2;
if (s<d)
{
m=(s+d)/2;
divide(s,m,cm1);
divide(m+1,d,cm2);
cm=cmmdc(cm1,cm2);
}
else
if (s==d) cm=a[s];
}
int main()
{
citire(a,n);
divide(1,n,cm);
cout<<"cmmdc = "<<cm;
}
3. Din fişierul NUMERE.IN se citesc 100 de numere întregi. Să se afişeze cea mai mare diferenţă în modul dintre
indicii elementelor egale.
Rezolvare:
Presupunem că elementele şirului sunt stocate în vectorul a. Funcţia divide realizează afişarea diferenţei
maxime în modul pentru indici corespunzători unor elemente egale ale şirului a cu capetele de indici s şi d. Metoda
presupune împărţirea problemei iniţiale în două sau mai multe subprobleme astfel: se calculează diferenţa maximă în
modul a indicilor corespunzători unor elemente egale din subşirurile cu capete de indici s+1, d, respectiv s, d-1. Se
compară aceste valori reţinându-se valoarea maximă:
max(divide(s+1,d),divide(s,d-1)).
Exemplu:
Pentru şirul de valori (2,4,5,6…,4,8,9) se va afişa valoarea 96.
#include<iostream>
#include<iomanip.h>
#include<fstream>
int a[30],n;
void citire(int a[],int &n)
{
int i;
ifstream f("div3.txt");
f>>n;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
int max(int a,int b)
{
if (a>b) return a;
else return b;
}
int divide(int s,int d)
{
if (a[s]==a[d]) return d-s;
else
if (s<d) return max(divide(s+1,d),divide(s,d-1));
}
int main()
{
citire(a,n);
cout<<"valoarea maxima = "<<divide(1,n);
}
4. Să se calculeze suma elementelor unui şir cu n valori citite dintr-un fişier text.
Rezolvare:
Funcţia divide calculează suma elementelor unui subşir cu capetele de indici s şi d, returnând valoarea minimă
în referinţa sum. Împărţirea şirului continuă până la obţinerea de subşiruri de un singur element (suma elementelor este
chiar elementul) (s=d). O astfel de suproblemă se obţine aplicând aceeaşi funcţie (recursiv) pentru calculul sumei
elementelor subşirurilor cu capete de indici s, m, respectiv m+1, d (m reţine indicele jumătăţii şirului). Soluţia finală se
obţine prin însumarea soluţiilor obţinute anterior.
Exemplu:
Pentru n=6 si a=(2,5,8,6,1,9) se va afişa valoarea 31.
#include<iostream>
#include<iomanip.h>
#include<fstream>
int a[30],n,sum;
void citire(int a[],int &n)
{
int i;
ifstream f("div4.txt");
f>>n;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
void divide(int s,int d,int &sum)
{
int m,sum1,sum2;
if (s<d)
{
m=(s+d)/2;
divide(s,m,sum1);
divide(m+1,d,sum2);
sum=sum1+sum2;
}
else
if (s==d) sum=a[s];
}
int main()
{
citire(a,n);
divide(1,n,sum);
cout<<"suma elementelor = "<<sum;
}
5. Se dă un şir cu n elemente numere naturale de cel mult 3 cifre. Să se calculeze suma elementelor cu proprietatea că
au 3 divizori.
Rezolvare:
Analog problemei anterioare, se împarte subşirul până la obţinerea de subşiruri de un singur element (s=d).
Pentru fiecare dintre aceste subşiruri se testează dacă elementul are exact 3 divizori. În caz afirmativ suma elementelor
cu exact 3 divizori pentru subşirul astfel obţinut (subproblemă elementară) este chiar elementul, în caz contrar, 0.
Pentru implementarea algoritmului am folosit următoarea deducţie logică: doar numerele pătrate perfecte de numere
prime au trei divizori. Funcţia verif testează dacă parametrul n este pătrat perfect, iar funcţia prim verifică dacă
parametrul n număr prim.
Exemplu:
Pentru n=7 si a=(3,4,6,5,25,43,49) se va afişa 78 .
#include<iostream>
#include<iomanip.h>
#include<fstream>
#include<math.h>
int a[30],n,sum;
void citire(int a[],int &n)
{
int i;
ifstream f("div5.txt");
f>>n;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
int prim(int n)
{
int i;
if((n==0)||(n==1)) return 0;
for(i=2;i<n/2;i++)
if (n%i==0) return 0;
return 1;
}
int verif(int n)
{
return (floor(sqrt(n))==sqrt(n)) &&
(prim(floor(sqrt(n))));
}
void divide(int s,int d,int &sum)
{
int m,sum1,sum2;
if (s<d)
{
m=(s+d)/2;
divide(s,m,sum1);
divide(m+1,d,sum2);
sum=sum1+sum2;
}
else
if (s==d)
if (verif(a[s])) sum=a[s];
else sum=0;
}
int main()
{
citire(a,n);
divide(1,n,sum);
cout<<"suma elementelor = "<<sum;
}
6. Problema căutării binare. Se citeşte dintr-un fişier text un şir cu n elemente cu proprietatea că elementele sunt în
ordine crescătoare. Să se verifice dacă o valoare v, citită de la tastatură, se găseşte sau nu printre elementele şirului.
Rezolvare:
Întrucât şirul dat este ordonat crescător, nu este necesar că comparăm valoarea dată cu fiecare element al şirului.
Pentru rezolvarea problemei utilizând metoda Divide et Impera folosim următorul algoritm: comparăm valoarea v cu un
element de la mijlocul şirului. În urma comparaţiei pot apărea situaţiile:
- valorile comparate sunt egale (căutarea se încheie);
- valoarea v este mai mică decât elementul din mijloc (căutarea continuă în jumătatea stângă a şirului dat);
- valoarea v este mai mare decât elementul din mijloc (căutarea continuă în jumătatea dreaptă a şirului dat).
Exemplu:
Pentru n=5, şirul a=(2,3,6,8,9) şi valoarea v=8 se va afişa un mesaj afirmativ, iar pentru n=4, şirul
a=(3,5,7,9) şi valoarea v=6 se va afişa un mesaj neafirmativ.
#include<iostream>
#include<iomanip.h>
#include<fstream>
int a[30],n,v,h;
void citire(int a[],int &n,int &v)
{
int i;
ifstream f("div6.txt");
f>>n>>v;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
void divide(int s,int d)
{
int m;
if (s<=d)
{
m=(s+d)/2;
if (a[m]==v) h=1;
else
if (v<a[m]) divide(s,m-1);
else divide(m+1,d);
}
}
int main()
{
citire(a,n,v);
h=0;
divide(1,n);
if (h) cout<<"valoarea se gaseste";
else cout<<"valoarea nu se gaseste";
}
7. Se citeşte un şir cu n elemente numere reale pozitive. Utilizând metoda Divide-et-Impera să se calculeze suma
valorilor naturale.
Rezolvare:
Algoritmul de rezolvare este similar celui folosit la problemele 4 şi 5 de la acest subcapitol, cu observaţia că o
componentă a şirului „participă“ la sumă doar dacă este număr natural (floor(a[s])==a[s]).
Exemplu:
Pentru n=5 si a=(3.4, 6, 78.9, 21, 3) se va afişa valoarea 30 .
#include<iostream>
#include<iomanip.h>
#include<math.h>
#include<fstream>
float a[30],sum;
int n;
void citire(float a[],int &n)
{
int i;
ifstream f("div7.txt");
f>>n;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
void divide(int s,int d,float &sum)
{
int m;
float sum1,sum2;
if (s<d)
{
m=(s+d)/2;
divide(s,m,sum1);
divide(m+1,d,sum2);
sum=sum1+sum2;
}
else
if (s==d)
if (floor(a[s])==a[s]) sum=a[s];
else sum=0;
}
int main()
{
citire(a,n);
divide(1,n,sum);
cout<<"suma elementelor naturale= "<<sum;
}
8. Se dă un şir cu n elemente numere întregi şi o valoare v. Să se determine numărul de apariţii al valorii v printre
elementele şirului utilizând metoda Divide-et-impera.
Rezolvare:
Algoritmul presupune împărţirea problemei iniţiale în două sau mai multe subprobleme astfel: se calculează
numărul de apariţii al valorii v în subşirurile cu capete de indici s, m, respectiv m+1, d (m - indicele jumătăţii).
Împărţirea problemei în subprobleme continuă până la obţinerea de subşiruri cu un singur element (d=s). Se compară
valoarea dată v cu elementul subşirului (a[s]) urmând a creşte numărul de apariţii al lui v în şir dacă între aceste două
valori există relaţia de egalitate. Numărul de apariţii este reţinut în referinţa nr.
Exemplu:
Pentru n=6, şirul a=(3,5,3,3,7,3) şi valoarea v=3 se va afişa valoarea 4 .
#include<iostream>
#include<iomanip.h>
#include<fstream>
int a[30],n,v,nr;
void citire(int a[],int &n,int &v)
{
int i;
ifstream f("div8.txt");
f>>n>>v;
for(i=1;i<=n;i++) f>>a[i];
f.close();
}
void divide(int s,int d,int &nr)
{
int m,nr1,nr2;
if (s<d)
{
m=(s+d)/2;
divide(s,m,nr1);
divide(m+1,d,nr2);
nr=nr1+nr2;
}
else
if (s==d) if (v==a[s]) nr=1;
else nr=0;
}
int main()
{
citire(a,n,v);
divide(1,n,nr);
cout<<"numarul de aparitii = "<<nr;
}
9. Se consideră o zonă dreptunghiulară dată prin lungime şi înălţime (Lp şi Hp), care sunt valori naturale. În zona
respectivă se dau coordonatele întregi ale unor găuri cu diametru neglijabil. Se cere să se decupeze din dreptunghi o
zonă de arie maximă care să nu conţină găuri. Dreptunghiul se va afişa prin coordonatele vârfului din stânga sus,
lungimea şi înălţimea sa.
Rezolvare:
Această problemă se deosebeşte de cele anterioare prin faptul că descompunerea prin metoda Divide et Impera se
realizează în 4 subprobleme. Altfel spus, dintr-o zonă dreptunghiulară ce conţine n găuri, o gaură oarecare i determină
alte 4 zone, zone care conţin cel mult n-1 găuri. Definim o placă prin coordonatele colţului din sânga sus (xs, ys),
lungime (l) şi înălţime (h). În implementarea algoritmului folosim funcţia este cu valoarea booleană, funcţie prin care
se verifică dacă o zonă conţine sau nu găuri.
#include<iostream>
#include<iomanip.h>
#include<fstream>
int x[30],y[30],n;
int lp,hp,amax,lmax,xmax,ymax,hmax;
void citire(int x[],int y[],int &n,int &lp,int &hp)
{
int i;
ifstream f("div9.txt");
f>>n>>lp>>hp;
for(i=1;i<=n;i++) f>>x[i];
for(i=1;i<=n;i++) f>>y[i];
f.close();
}
int este(int i,int xs,int ys,int l,int h)
{
return
((x[i]>xs)&&(y[i]>ys)&&(x[i]<xs+l)&&(y[i]<ys+h));
}
13. Problema turnurilor din Hanoi. Se consideră 3 tije A,B,C. Pe tija A se găsesc n discuri de diametre diferite aşezate în
ordine descrescătoare, după diametru, de jos în sus. Să se deplaseze discurile de pe tija A pe tija B utilizând tija C, dar să nu
existe situaţie în care un disc cu diametru mai mare să se găsească peste un disc cu diametrul mai mic.
Rezolvare:
Notăm cu h(a,b,c,n) mulţimea mutărilor necesare pentru trecerea celor n discuri de pe tija a pe b, folosind
tija intermediară c şi mutatea unui disc de pe tija a pe b o notăm cu a->b. Exemplificăm pentru 3 discuri: primele
două discuri trec pe tija intermediară c, apoi se muta discul cu diametru maxim de pe tija a pe tija finală b, după care se
trec şi discurile de pe tija c pe tija b folosind de această dată tija a, pentru manevră.
Pe caz general (n discuri):
- se mută primele n–1 discuri pe tija intermediară;
- se mută discul de diametru maxim pe tija finală;
- se mută cele n–1 discuri de pe tija intermediară pe cea finală.
În rezolvarea problemei, la apelul funcţiei hanoi am înlocuit parametri formali a,b,c cu valorile 1, 2,
respectiv 3.
#include<iostream>
int n;
void hanoi(int a,int b,int c,int n)
{
if (n>0)
{
hanoi(a,c,b,n-1);
cout<<a<<"->"<<b<<endl;
hanoi(c,b,a,n-1);
}
}
int main()
{
cout<<"n=";cin>>n;
hanoi(1,2,3,n);
}
14. Se consideră o zonă pătratică de dimensiune putere a lui 2, care este împărţită în pătratele de lungime egală cu
unitatea. Cunoscând coordonatele unui pătrăţel deja haşurat să se haşureze toată zona cu forme ca în desenul alăturat.
Rezolvare:
Algoritmul de rezolvare este similar celui prezentat la problema 9 de la acest subcapitol, în sensul că
descompunerea se realizează în 4 subprobleme. Pentru implementarea algoritmului declarăm o matrice, prezenţa unor
elemente nule în matrice (verificarea se face prin intermediul subprogramului exista) permiţând haşura unei zone cu
configuraţia impusă.
#include<iostream>
#include<iomanip.h>
int a[50][50],i,j,x,y,p,l;
int exista(int x,int y,int m)
{
for(i=x;i<x+m;i++)
for(j=y;j<y+m;j++)
if (a[i][j]!=0) return 1;
return 0;
}
void umple(int x,int y,int l)
{
int m;
if (l>1)
{
m=l/2;
p++;
if (exista(x,y,m))
{
a[x+m-1][y+m]=p;
a[x+m][y+m-1]=p;
a[x+m][y+m]=p;
}
else
if (exista(x,y+m,m))
{
a[x+m-1][y+m-1]=p;
a[x+m][y+m-1]=p;
a[x+m][y+m]=p;
}
else
if (exista(x+m,y,m))
{
a[x+m-1][y+m-1]=p;
a[x+m-1][y+m]=p;
a[x+m][y+m]=p;
}
else
if (exista(x+m,y+m,m))
{
a[x+m-1][y+m-1]=p;
a[x+m-1][y+m]=p;
a[x+m][y+m-1]=p;
}
umple(x,y,m);
umple(x,y+m,m);
umple(x+m,y,m);
umple(x+m,y+m,m);
}
}
int main()
{
cout<<"l=";cin>>l;
cout<<"x=";cin>>x;
cout<<"y=";cin>>y;
a[x][y]=1;
p=1;
umple(1,1,l);
for(i=1;i<=l;i++)
{
for(j=1;j<=l;j++)
cout<<setw(4)<<a[i][j];
cout<<endl;
}
}
15. Se consideră un polinom P(x) de gradul n dat prin coeficienţii şi o valoare v. Utilizând metoda Divide-et-Impera,
să se calculeze valoare polinomului în punctul v.
Rezolvare:
Reţinem coeficienţii polinomului în şirul a, şir care va fi supus împărţirii în subşiruri conform principiului Divide
et Impera. Împărţirea continuă până la obţinerea de subşiruri cu un singur element, element ce constituie coeficientul
unui monom. Se calculează valorilor monoamelor astfel obţinute, urmând ca valoarea polinomului să fie reprezentată de
suma valorilor monoamelor.
#include<iostream>
#include<iomanip.h>
#include<fstream>
#include<math.h>
int a[30],n,v;
float rez;
void citire(int a[],int &n,int &v)
{
int i;
ifstream f("div15.txt");
f>>n>>v;
for(i=n;i>=0;i--) f>>a[i];
f.close();
}
void divide(int s,int d,float &rez)
{
int m;
float r1,r2;
if (s<d)
{
m=(s+d)/2;
divide(s,m,r1);
divide(m+1,d,r2);
rez=r1+r2;
}
else
if (s==d) rez=a[s]*pow(v,s);
}
int main()
{
citire(a,n,v);
divide(0,n,rez);
cout<<"valoarea polinomului = "<<rez;
}