Divide Et Impera Apli
Divide Et Impera Apli
Divide Et Impera Apli
Putem considera problema iniţială ca un şir de elemente xp, xp+1, xp+2, … , xq-1, xq
(p ≤ q) asupra căruia trebuie făcută o prelucrare oarecare.
Rezolvarea problemei:
1
p + q
(1) Se calculează mijlocul şirului: m = .
2
(2) Se aplică algoritmul Divide – et – Impera pentru prima jumătate, adică pentru
subşirul xp, xp+1, xp+2, … , xm (p ≤ m).
(3) Se aplică algoritmul Divide – et – Impera pentru a doua jumătate, adică
pentru subşirul xm+1, xm+2, … , xq (m < q).
Pentru fiecare subşir se va obţine câte o soluţie.
Notă: Se poate opta ca elementul din mijloc (în cazul în care şirul are număr
impar de elemente) să fie în primul subşir şi, în consecinţă, se vor lua în
considerare subşirurile xp, xp+1, xp+2, … , xm+1 (p< m). xm, xm+1, … , xq (m≤q).
(4) Cele două soluţii se vor combina pentru a obţine soluţia şirului iniţial.
Observaţie:
d = gradul de detaliu pentru care problema poate fi rezolvată uşor (de obicei are
valoarea 1)
α = soluţia şirului iniţial
β = soluţia primului subşir
γ = soluţia celui de-al doilea subşir
Notă: Ceea ce trebuie avut în vedere la metoda Divide – et – Impera (şi acest
aspect se va repeta şi la alte metode de programare) este faptul că problema nu
trebuie privită în ansamblu, ci impărţită intr-o problemă mai mică şi rezolvată doar
privind din perspectiva problemei mici (adică ce se întâmplă în acel moment). Dacă
algoritmul este descris corect si recursivitatea merge bine, atunci cu siguranţă şi
soluţia problemei mari (iniţială) va fi corectă.
3. Aplicaţii
C =C +C
k k −1 k
n n −1 n −1
#include <conio.h>
#include <stdio.h>
2
unsigned int comb(unsigned int n, unsigned int k)
{
if ((k==0) || (k==n)) return 1; //condiţii de oprire
else return comb(n-1, k-1)+comb(n-1,k); //apelul recursiv (de 2 ori)
}
void main()
{
unsigned int n, k;
printf("n=");
scanf("%u",&n);
do
{
printf("k=");
scanf("%u",&k);
}
while (k>n);
printf("%u",comb(n,k)); //apelarea funcţiei recursive
getch();
}
n=6
k=2
comb(6,2)=comb(5,1)=5 +comb(5,2)*=10
/
1 comb(4,0)+comb(4,1)
/
1 comb(3,0)+comb(3,1)
/
1 comb(2,0)+comb(2,1)
/
comb(1,0)+comb(1,1)=1+1=2
comb(5,2)* =comb(4,1)+ comb(4,2)=6
/ \
comb(3,0)+comb(3,1)=4 comb(3,1)=3 +comb(3,2)
/
3
comb(2,1)+comb(2,2)=3
#include <conio.h>
#include <stdio.h>
int v[50];
void main()
{
unsigned int n;
citire(v,n);
printf("%d",suma(0,n-1));
getch();
}
4
Pentru a calcula suma elementelor dintr-un vector utilizând metoda Divide – et –
Impera se împarte (vectorul delimitat de capetele i şi j) in 2 subvectori de dimensiuni
aproximativ egale (în cazul în care vectorul iniţial are număr impar de elemente, atunci
cel de-al doilea subvector va avea cu un element in plus), delimitaţi de capetele i, m şi
j, se calculează pentru fiecare dintre aceşti doi subvectori suma elementelor, se obţin
2 sume care se adună pentru a obţine suma finală (a tuturor elementelor).
În cazul în care subvectorul are un singur element, atunci suma va fi egală cu
valoarea acelui element (condiţia de oprire).
Trebuie acordată o mare atenţie variabilelor locale din funcţie deoarece acestea
se restaurează din stivă de fiecare dată când se revine din apelul recursiv. Dacă
aceste variabile ar fi globale atunci nu s-ar mai calcula corect soluţia problemei.
Exemplu
#include <conio.h>
#include <stdio.h>
unsigned int v[50];
5
}
}
void main()
{
unsigned int n;
citire(v,n);
printf("%u", cmmdc(0,n-1));
getch();
}
Exemplu
#include <conio.h>
#include <stdio.h>
int v[50];
unsigned int i;
do
printf("n=");
scanf("%d",&n);
while (n>=50);
6
for (i=0; i<n; i++)
printf("v[%u]=",i);
scanf("%d",&v[i]);
unsigned int m, a, b;
else {
m=(i+j)/2;
a=max(i, m);
b=max(m+1,j);
if (a>b) return a;
else return b;
void main()
unsigned int n;
citire(v,n);
printf("%d", max(0,n-1));
getch();
7
Aceeaşi idee de rezolvare ca la suma elementelor dintr-un vector şi
determinarea celui mai mare divizor comun al elementelor dintr-un vector.
#include <conio.h>
#include <stdio.h>
void main()
{
unsigned int n;
char a='a', b='b', c='c';
printf("n=");
scanf("%u",&n);
Hanoi(n,a,b,c);
getch();}
Exemplu: n=3
• se mută discul rămas pe tija a (diametrul cel mai mare) pe tija b. În acest
fel s-a eliberat tija a şi poate fi utilizată pentru a manevra cele 2 discuri de
pe tija c.
• se mută primul disc (diametrul cel mai mic) pe tija c pe tija a. În acest fel
s-a eliberat discul cu diametrul mijlociu şi poate fi mutat la locul lui final.
10
Tija Tija Tija
a b c
• se mută discul cu diiametrul cel mai mic pe tija a pe tija b.
Se procedează în acelaşi mod şi pentru valori mai mari ale lui n, doar că
numărul de mutări va fi mult mai mare.
11
6) Problema tăieturilor2: Se dă o bucată dreptunghiulară de tablă cu lungimea
L şi înălţimea H (L şi H fiind două numere naturale citite de la tastatură), pe
care ne-o imaginăm aşezată în cadranul I al unui sistem cartezian de
coordonate, cu un colţ al bucăţii de tablă în originea O. Bucata de tablă are
pe suprafaţa ei n găuri de coordonate numere naturale (valori citite dintr-un
fişier text). Se cere să se decupeze din tablă o bucată dreptunghiulară de
arie maximă care nu conţine găuri. Precizăm ca diametrul unei găuri
oarecare este suficient de mic astfel încât în urma unei tăieturi pe o direcţie
care conţine o gaură se obţin margini drepte, nu ondulate.
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int x[50],y[50],n,H,L;
int aria_max=0,x_max,y_max,h_max,l_max;
void citire()
{
unsigned int i;
FILE *f;
f=fopen("pliere.txt","r");
if (f!= NULL)
{
fscanf(f,"%d%d",&H,&L);
fscanf(f,"%d",&n);
for(i=0;i<n;i++)
fscanf(f,"%d%d",&x[i],&y[i]);
}
fclose(f);
}
Placa inţială are colţul din stânga jos în punctul de coordonate (0, 0),
lungimea L şi înălţimea H, conform desenului de mai jos. Pe această placă se găsesc n
găuri ale căror coordonate sunt păstrate în vectorii x (coodonata x) şi y (coordonata y).
(0, 0) L X
13
funcţiei găsit. Această funcţie verifică daca un anumit punct, de coordonate (x[i], y[i]),
se încadrează în grafic între limitele plăcii curente.
Parcurgerea găurilor din placă se face în cadrul funcţiei taie (funcţia care
implementează algoritmul de divizare). În cazul în care nu se mai găseşte nici o gaură
în placă atunci se consideră şirul apelurilor recursive încheiat, s-a ajuns la o placa fără
găuri, i se calculează acesteia aria şi în cazul în care aria acestei bucăţi de placă este
mai mare decât cea presupusă maximă se actualizează variabilele pentru aria maximă,
coordonatele colţului stânga-jos al plăcii finale, lăţimea şi înălţimea acesteia.
Să presupunem că pe placă se găseşte o gaură de coordonate (x[i], y[i]),
conform desenului de mai jos.
yp+hp
y[i]
yp
(0, 0) X
xp x[i] xp+lp
Astfel, placa poate fi tăiată în două moduri: printr-o linie orizontală şi printr-o
linie vertical. Pentru a găsi porţiunea din placă de arie cea mai mare vor
trebui luate în considerare toate modalităţile de tăiere. În urma fiecărei tăieri
se obţin câte 2 plăci mai mici, deci, în final vor fi 4 variante.
Dacă se taie placa printr-o linie orizontală se obţin, co
Y
yp+hp
y[i]
yp
14
Y
yp+hp
y[i]
yp
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int v[50];
{int ms,md;
char *sir3="";
3
Olimpiada nationala, Arad, 1992 - text modificat. Sursa: “Informatica, manual pentru clasa
aX-a”, Emanuela Cherchez, Mainel Şerban Ed. Polirom, Iaşi, 2000
15
puts(s); }
else {
if ((j-i+1)%2!=0) ms=(i+j)/2-1;
else ms=(i+j)/2;
md=(i+j)/2+1;
itoa(ms,sir3,10);
strcat(sir3," " );
strcat(strcat(s,"S"),sir3);
pliere(i,ms,s);
s[strlen(s)-3]=NULL;
itoa(md,sir3,10);
strcat(sir3," " );
strcat(strcat(s,"D"),sir3);
pliere(md,j,s);
s[strlen(s)-3]=NULL;
void main()
{int n,i;
char *s="";
do{
printf("n=");
scanf("%d",&n);
16
}while ((n<=0)||(n>=50));
{printf("v[%u]=",i);
scanf("%d",&v[i]);}
pliere(1,n,s);
getch();
4
Termenul fractal provine din latinescul fractus, care înseamnă "spart“, "fracturat" (termen
introdus de Benoît Mandelbrot, în 1975) – sursa Wikipedia
17
• Psihologii vorbesc de aşa numitele boli dinamice ce apar în momentul
desincronizării fractalilor, sau cum ar spune medicina indiană – atunci când omul
iese din armonia Universului.
• Cu ajutorul simulărilor fractale (sau fractaliere) ale lui Mandelbrot a fost posibilă
prezicerea cu mare exactitate a variaţiei preţului de bursă al bumbacului.
• Geneticienii sunt convinşi că molecula ADN/DNA este unul dintre cele mai
complicate modele fractale existente în natură şi reprezintă prin excelenţă acea
“similaritate cu sinele cât şi principiul “părţii asemănătoare cu întregul”.
• Fractalii sunt de asemenea predominanţi în arta şi arhitectura africană. Casele
circulare apar în cercuri de cercuri, casele dreptunghiulare în dreptunghiuri de
dreptunghiuri şi aşa mai departe. Astfel de tipare se găsesc şi în textile şi
sculpturile africane, precum şi în părul împletit în codiţe
#include <graphics.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <dos.h>
int l2;
l2=l/2;
rectangle(x-l2,y-l2,x+l2,y+l2);
delay(500);
circle(x,y,r);
delay(500);
const c=3.3;
int l2,l3;
if (l>0){
patrat(x,y,l);
cerc(x1,y1,r);
l2=l/2;
l3=floor(l/c);
r=r/2;
diamant(x-l2,y,l3,x1-l2,y1-l2,r);
int main(void)
errorcode = graphresult();
if (errorcode != grOk)
getch();
exit(1); }
getch();
closegraph();
return 0;
Enunţ
Fie un şir de n numere intregi (n≥1) cu proprietatea că sunt ordonate
crescător şi o valoare întreagă x. Să se verifice dacă valoarea x se află
printre elementele vectorului, afişându-se pe ecran un mesaj corespunzător.
20
Soluţie
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void citire()
{
unsigned int i;
FILE *f;
f=fopen("cautare.txt","r");
if (f!= NULL)
{
fscanf(f,"%d",&n);
for(i=0;i<n;i++)
fscanf(f,"%d",&v[i]);
fscanf(f,"%d",&x);
}
fclose(f);
}
Soluţie
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void citire()
{
int i;
FILE *f;
f=fopen("intercl.txt","r");
if (f!= NULL)
{
fscanf(f,"%d",&n);
for(i=0;i<n;i++)
fscanf(f,"%d",&v[i]);
}
fclose(f);
}
void afisare()
{
int i;
for (i=0; i<n; i++)
printf("%d ",v[i]);
printf("\n");
}
void main()
{
int p;
citire();
afisare();
MergeSort(0,n-1);
afisare();
getch();
}
Enunţ
Fie un şir de n numere intregi (n≥1). Să se ordoneze crescător numerele
citite folosind metoda sortării rapide (Quick Sort).
Soluţie
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void citire()
{
int i;
FILE *f;
f=fopen("quick.txt","r");
if (f!= NULL)
{
fscanf(f,"%d",&n);
23
for(i=0;i<n;i++)
fscanf(f,"%d",&v[i]);
}
fclose(f);
}
void afisare()
{
int i;
for (i=0; i<n; i++)
printf("%d ",v[i]);
printf("\n");
}
void main()
{
int p;
24
citire();
afisare();
QuickSort(0,n-1);
afisare();
getch();
}
25