Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
VIZAT Prof. Univ. Dr. Rodica TRANDAFIR Conf. Univ. Dr. Rodica IOAN
FISA DISCIPLINEI
I.
UNIVERSITATEA SPIRU HARET
FACULTATEA MATEMATICA-INFORMATICA
DOMENIUL DE LICENTA INFORMATICA
SPECIALIZAREA INFORMATICA
Anul universitar 2008 - 2009
Forma de invatamant ZI
II.
DENUMIRE DISCIPLINA TEHNICI AVANSATE DE PROGRAMARE
III.
CODUL DISCIPLINEI
IV.
Statut disciplina Obligatorie Optionala Facultativa
(se marcheaza cu X) X
V. Structura disciplinei (nr. ore)
Semestrul Curs Seminar Laborator Lucrari practice Proiecte
(numar de (nr. ore/sapt. (nr. ore/sapt. (nr. ore/sapt. (nr. ore/sapt. (nr. ore/sapt.
la 1 la 6) si total si total si total si total si total
nr.ore/sem.) nr.ore/sem.) nr.ore/sem.) nr.ore/sem.) nr.ore/sem.)
4 2/28 - 2/28 - -
VI.(ETCS)
Numar credite 6
VII.
OBIECTIVELE DISCIPLINEI
1. Valorificarea cunostintelor acumulate in cadrul cursurilor de Programare Procedurala,
Algoritmi si Structuri de date, Proiectare si Programare Orientata Obiect in vederea
programarii unor algoritmi avansati elaborati cu metode specifice.
2. Crearea deprinderilor de a gandi si programa folosind sabloane (templates)
3. Insusirea unor algoritmi avansati in domeniul prelucrarii sirurilor.
4. Cresterea capabilitatii in utilizarea in programarea generica a limbajelor C++ si Java.
5. Asigurarea compatibilitatii cu invatamantul de excelenta : University of Cambridge
(http://www.cl.cam.ac.uk/DeptInfo/CST05/node30.html); Imperial College London
(http://www3.imperial.ac.uk/computing/teaching/undergraduate/computing/lectures);
Princeton University (http://www.cs.princeton.edu/academics/catalog/ugrad)
VIII.
CONTINUT TEMATIC
I. Structuri de date fundamentale (Recapitulare)
II. Metode avansate de proiectarea algoritmilor:
1. Recursivitate
2. Metoda Greedy
3. Metoda Backtracking
4. Metoda Divide et impera
5. Metoda Programării dinamice
6. Metoda Branch&Bound.
7. Procesarea sirurilor
IX.
TEME SEMINAR
-
X.
LUCRARI DE LABORATOR
1. Metode de elaborarea algoritmilor (14 ore)
2. Biblioteca Standard de Sabloane (STL) a limbajului C++ (6 ore)
3. Cautare in siruri (2 ore)
4. Programare generica in Java (6 ore).
XI.
LUCRARI PRACTICE
-
XII.
PROIECTE
-
XIV. Bibliografie
Obligatorie minimala Suplimentara Facultativa
1. Albeanu G., Algoritmi si 1. Java, Using and 1. N.M. Josuttis, The C++
limbaje de programare, Programming Generics Standard Library, Addison-
Editura FRM, 2000 (pag. 207- in J2SE 5.0, Wesley, 1999.
233) http://java.sun.com/devel 2. A. Drozdek, Data structures
2. Albeanu G. (coord), L. oper/technicalArticles/J2 and algorithms in C++,
Rapeanu, L. Radu, A. SE/generics/ Brooks/Cole, 2001.
Averian, Tehnici de 2. C. Galatan, 3. Roberge J., Brandle S.,
programare, Editura FRM, Introducere in C++ Whittington D., A laboratory
2003. Standard Template course in C++ data structures
3.Doina Logofatu, Algoritmi Library, Ed. All, 2008. (ed. 2), Jones and Bartlett
fundamentali in Java/C++. 3. R. Neapolitan, K. Publishers, 2003.
Aplicatii. Polirom, 2007 Naimipour ,
(integral). Foundations of
4. Valeriu Iorga, Cristian Algorithms Using C++
Opincaru, Corina Stratan, Pseudocode, Jones and
Alexandru Chirita, Structuri Bartlett Publishers, 2004.
de date si algoritmi. Aplicatii
in C++ folosind STL,
Polirom, 2005.
XV.
Metode didactice (clasice/moderne)
1. Prelegerea - proiecţie in amfiteatru, programe demonstrative;
2. Recomandarea, pentru studiul individual, a unor paragrafe din bibliografia indicată, în
vederea aprofundării sau extinderii cunoştinţelor căpătate la curs/laborator ;
3. Prezentarea unor exemple şi a unor probleme aplicative în cadrul cursului pentru sporirea
interesului cursantilor.
4. Evaluare folosind platforma Blackboard.
_______________________
2. Structuri de date
O structură de date este o mulţime de date organizate într-un anumit
mod împreună cu relaţiile dintre acestea.
În funcţie de modul de alocare, structurile de date se clasifică în:
• structuri de date statice : tabloul, înregistrarea, mulţimea, fişierul.
Structurile de date statice ocupă o zonă de memorie constantă pe
toată durata de executare a blocului în care apare declaraţia şi
elementele ocupă poziţii fixe. Fişierele sunt structuri de date
externe (vezi capitolul 1).
• structuri de date semistatice: stiva alocată static, coada alocată
static. Structurile de date semistatice ocupă o zonă de memorie de
dimensiune constată, alocată pe toată durata executării blocului în
care apare declaraţia de structură, iar elementele ocupă poziţii
variabile pe parcursul executării programului.
• structuri de date dinamice: lista înlănţuită, structuri arborescente.
Structurile de date dinamice ocupă o zonă de memorie de
dimensiune variabilă, alocată dinamic. Alocarea dinamică permite
gestionarea memoriei în timpul executării programului. Ele sunt
mult mai flexibile decât cele statice şi din această cauză sunt
extrem de avantajoase.
Liste: O listă este o colecţie de elemente de informaţie (noduri)
aranjate într-o anumită ordine. Lungimea unei liste este numărul de
noduri din listă. Structura corespunzătoare de date trebuie să ne
permită să determinăm eficient care este primul/ultimul nod în
structură şi care este predecesorul/succesorul (dacă există) unui nod
dat. Limbajele Pascal sau C(++) oferă posibilităţi de implementare a
acestor structuri atât static cât şi dinamic. Operaţiile curente care se
fac în liste sunt: inserarea unui nod, ştergerea (extragerea) unui nod,
concatenarea unor liste, numărarea elementelor unei liste etc.
Implementarea unei liste se poate face în principal în două moduri:
• Implementarea secvenţială, în locaţii succesive de memorie,
conform ordinii nodurilor în listă. Avantajele acestei tehnici
sunt accesul rapid la predecesorul/succesorul unui nod şi
găsirea rapidă a primului/ultimului nod. Dezavantajele sunt
inserarea/ştergerea relativ complicată a unui nod şi faptul că
nu se foloseşte întreaga memorie alocată listei.
• Implementarea înlănţuită. Fiecare nod conţine două părţi:
informaţia propriu-zisă şi adresa nodului succesor. Alocarea
31
memoriei fiecărui nod se poate face în mod dinamic, în timpul
rulării programului. Accesul la un nod necesită parcurgerea
tuturor predecesorilor săi, ceea ce poate lua ceva mai mult
timp. Inserarea/ştergerea unui nod este, în schimb, foarte
rapidă.
Listele se pot clasifica după numărul de legături în:
• liste simple
• liste duble
• liste circulare
O listă simplă are o singură legătură, legătura ultimului element este
adresa NIL/NULL. Pentru a accesa lista avem nevoie de o variabilă
care să păstreze adresa primului element (cap sau prim). O listă
dublă are două legături: legătura de tip următor şi legătura de tip
precedent sau anterior. O lista circulară este o lista în care, după
ultimul nod, urmează primul, deci fiecare nod are succesor şi
predecesor.
Listele se pot clasifica după locul în care se fac operaţiile de
adăugare/eliminare astfel:
• stive
• cozi
Între nodurile unei liste simplu înlănţuite este definită o singură relaţie
de ordonare. Fiecare nod conţine un pointer a cărui valoare reprezintă
adresa nodului următor din listă.
Limbajul Pascal
Limbajul C(++)
type lista = ^nod typedef struct nod {
nod=record tip inf;
inf:tip ; struct nod *urm;
urm: lista; }lista;
end;
unde urm este adresa următorului nod (pointer către următorul nod),
iar inf este un câmp de informaţie utilă.
Operaţii asupra listei simplu înlănţuite
Crearea unei liste simplu înlănţuite:
1. Se iniţializează pointerul prim cu Nil/NULL, deoarece lista la
început este goală;
2. Se rezervă zonă de memorie în memoria heap pentru nodul curent;
32
3. Se încarcă nodul curent cu date;
4. Se determină adresa ultimului nod şi se realizează legătura cu
nodul creat;
5. Se reia cu pasul 2 dacă se introduce un nod nou.
Inserarea unui element x al cărui câmp cheie a fost iniţializat în
faţa unei liste înlănţuite
LISTA-INSEREAZA(p,x)
1: urm(x) ←p
2: dacă p<>NIL atunci p←x
Căutarea într-o listă înlănţuită p a elementului x se realizează
prin subprogramul LISTA-CAUTA şi returnează pointerul la acest
obiect.
LISTA-CAUTA(p,x)
1. q←p
2. cât timp q<>NIL şi cheie(q)<>x execută q←urm(q)
3. returnează q
Probleme rezolvate
1. Fiind dată o listă simplu înlănţuită cu elemente numere întregi să se
realizeze un program care să execute următoarele operaţii: crearea,
parcurgerea, adăugarea unui nod la începutul listei, adăugarea unui nod
la sfârşitul listei, ştergerea unui nod de pe o poziţie dată.
Observaţii:
Limbajul Pascal: Limbajul C(++)
Procedura NEW(pointer)- alocarea Funcţia MALLOC se foloseşte
dinamică a memoriei pentru pentru a rezerva octeţi din
variabila dinamică pointer. memoria heap. Trebuie inclus
Procedura DISPOSE(pointer)- fişierul antet: stdlib.h sau
eliberarea memoriei ocupate de alloc.h
către variabila dinamică pointer.
Rezolvare:
Parcurgerea unei liste liniare simplu înlănţuite se realizează cu un
pointer care pleacă de la capul listei şi va referi pe rând fiecare nod,
prelucrând informaţiile din nod apoi se trece la următorul nod, prelu-
crăm informaţiile din nod etc.
33
Ştergerea unui nod de pe o poziţie dată p din interiorul listei se
realizează astfel: se parcurge lista până la pozitia p-1, se păstrează
nodul de pe poziţia p, se realizează legătura între nodul p-1 şi p+1 şi,
apoi se eliberează memoria ocupată de nodul p.
Implementare în Pascal:
type lista=^nod;
nod=record inf:integer; urm:lista end;
var p,x:integer;cap:lista;{adresa primului nod al listei}
procedure adaug(var cap:lista;x:integer); {adaugarea la sfarsitul listei}
var nou,q:lista;
begin
new(nou);nou^.inf:=x;nou^.urm:=nil;
if cap=nil then cap:=nou
else begin
q:=cap;
while q^.urm<> nil do q:=q^.urm;
q^.urm:=nou;
end;
end;
procedure adaug_inc(var cap:lista;x:integer); {adaugarea la inceput}
var nou:lista;
begin
new(nou);nou^.inf:=x;nou^.urm:=nil; {crearea nodului nou}
if cap=nil then cap:=nou
else begin
nou^.urm:=cap;cap:=nou;
{realizarea legaturii si primul nod devine nodul creat}
end;
end;
procedure listare(cap:lista);{listarea listei}
var t:lista;
begin
t:=cap;
while t<>nil do begin
write(t^.inf,' '); {prelucrarea informatiei}
t:=t^.urm; {trecerea la urmatorul nod}
end;
end;
procedure sterge(var cap:lista; p:integer);
34
{stergerea nodului de pe pozitia p}
var q,w,t:lista;i:integer;
begin
if cap=nil then writeln('Lista vida !!! ')
else if p=1 then begin
{stergere la inceputul listei}
q:=cap; cap:=cap^.urm; dispose(q);
end
else if (cap<> nil) then begin
t:=cap; i:=1;
while (t^.urm<> nil) and (i+1<p) do
begin inc(i) ;t:=t^.urm end;
if t^.urm=nil then write('nu exista suficiente pozitii')
else begin
w:=t^.urm; t^.urm:=t^.urm^.urm;
dispose(w)
end
end
end;
begin
read(x);
while x<>0 do begin adaug_inc(cap,x); read(x); end;
listare(cap);
write('pozitia');read(p);sterge(cap,p);
listare(cap);
write('informatia adaugata la sfarsit');read(x);adaug(cap,x);
listare(cap)
end.
Implementare în C:
#include <stdio.h>
#include<stdlib.h>
#include<alloc.h>
typedef struct nod {
int inf;
struct nod*urm;
}lista;
lista *prim;
lista *creare(void);
void parcurgere(lista *p);
35
lista* sterg_inc(lista *prim){
lista *p;
p=prim;
prim=prim->urm;
free(p);
return prim;
}
void adauga(lista*prim) {
/*adauga un nod la o lista simplu inlantuita
si returneaza pointerul spre nodul adaugat sau zero daca nu s-a realizat
adaugarea*/
lista *p,*q;
for (p=prim;p->urm!=NULL;p=p->urm)
q=(lista*) malloc(sizeof(q));
scanf("%d",&q->inf);
q->urm=NULL;
p->urm=q;
}
void main(){
lista *prim;
prim=creare(); parcurgere(prim); prim=sterg_inc(prim);
printf("\n");
parcurgere(prim); adauga(prim); parcurgere(prim);
}
lista *creare(){
int n,i,inf; lista *prim,*p,*q;
printf("nr. de elemente");scanf("%d",&n);
printf("informatia primului nod"); scanf("%d",&inf);
prim=(lista*)malloc(sizeof(prim)); prim->inf=inf;prim->urm=NULL;
for(q=prim,i=2;i<=n;i++){
printf("inf . %d:",i);scanf("%d",&inf);
p=(lista*)malloc(sizeof(p));
p->inf=inf;p->urm=NULL; q->urm=p; q=p;
}
return(prim);
}
void parcurgere(lista *p){
lista *q;
for (q=p;q;q=q->urm) printf("%d ",q->inf);
}
36
2. Inversarea legăturilor într-o listă simplu înlănţuită.
Rezolvare:
Se parcurge lista iniţială folosind trei variabile dinamice p1, p2, p3
care vor face referire la elementele consecutive din listă. p1 va fi
capul listei modificate.
Implementare Pascal:
program invers;
type lista=^nod;
nod=record inf:integer; urm:lista end;
var i,n,x:integer; p:lista;
procedure creare(var p:lista; x:integer);
var q:lista;
begin
if p=nil then begin new(p); p^.inf:=x; p^.urm:=nil end
else begin
q:=p; while q^.urm<>nil do q:=q^.urm;
new(q^.urm); q^.urm^.inf:=x; q^.urm^.urm:=nil;
end;
end;
procedure listare(p:lista);
var q:lista;
begin
q:=p; while q<>nil do begin write(q^.inf,' '); q:=q^.urm end;
end;
function inversare(p:lista):lista; Subprogramul de inversare în C:
var p1,p2,p3:lista; lista* invers(lista*p){
begin lista *p1,*p2,*p3;
p1:=p; p1=p;
p2=p->urm;
p2:=p^.urm;
p->urm=NULL;
p^.urm:=nil;
while (p2){
while p2<>nil do begin
p3=p2->urm;
p3:=p2^.urm;
p2->urm=p1;
p2^.urm:=p1;
p1=p2;
p1:=p2; p2=p3;
p2:=p3; }
end; return p1;
inversare:=p1; }
end;
37
begin
read(n);
for i:=1 to n do begin read(x); creare(p,x) end;
listare(p);writeln;
p:=inversare(p);
listare(p)
end.
Rezolvare:
Lista are ca informaţie gradul şi coeficientul fiecărui termen de
coeficient nenul. Pentru a calcula suma este necesar să parcurgem
listele celor două polinoame şi să adăugăm corespunzător în cea de-a
treia listă.
Implementare Pascal:
type lista=^nod;
nod=record grad:1..5000; coef:integer; urm:lista end;
var a,b,p,q,r:lista;
i,n,m:integer;
procedure creare(var p:lista);
begin
write('cati coeficienti nenuli are polinomul');readln(n);
new(p);readln(p^.coef,p^.grad);
p^.urm:=nil;b:=p; {b este adresa ultimului nod}
for i:=2 to n do begin
new(a);
write('coef ',i,':');readln(a^.coef); write('grad ',i,':');readln(a^.grad);
b^.urm:=a; b:=a; b^.urm:=nil
end
end;
procedure listare(p:lista);
var a:lista;
begin
a:=p;
while a<>nil do begin write(a^.coef,'x^', a^.grad,' +'); a:=a^.urm end;
writeln(#8,' ');
end;
38
procedure aduna(p,q:lista;var r:lista);
var a,b,c,d:lista;
begin
a:=p;b:=q; {c este adresa ultimului nod pentru lista suma}
while (a<>nil) and (b<>nil) do
if a^.grad=b^.grad then begin
if r=nil then begin
new(c);c^.grad:=a^.grad;
c^.coef:=a^.coef +b^.coef;
r:=c; r^.urm:=nil;
end
else begin
new(d); d^.grad:=a^.grad;
d^.coef:=a^.coef+b^.coef;
c^.urm:=d;c:=d;c^.urm:=nil
end;
a:=a^.urm;b:=b^.urm;
end
else if a^.grad<b^.grad then begin
if r=nil then begin
new(c); c^.grad:=a^.grad;
c^.coef:=a^.coef ; r:=c; r^.urm:=nil;
end
else begin
new(d); d^.grad:=a^.grad; d^.coef:=a^.coef;
c^.urm:=d;c:=d;c^.urm:=nil;
end;
a:=a^.urm;
end
else begin
if r=nil then begin
new(c);c^.grad:=b^.grad;
c^.coef:=b^.coef;r:=c;r^.urm:=nil;
end
else begin
new(d); d^.grad:=b^.grad; d^.coef:=b^.coef;
c^.urm:=d;c:=d;c^.urm:=nil;
end;
b:=b^.urm;
end;
39
if a<>nil then c^.urm:=a;
if b<>nil then c^.urm:=b;
end;
begin
creare(p);creare(q);listare(p);listare(q);
r:=nil;
aduna(p,q,r);
listare(r);
readln;
end.
Exerciţii:
1. Să se implementeze în C aplicaţia de mai sus.
2. Să se scrie un subprogram pentru calcularea produsului a două
polinoame rare.
3. Să se calculeze valoarea unui polinom într-un punct dat.
Indicaţie:
Calcularea produsului se va face prin parcurgerea tuturor perechilor de
termeni astfel:
-fiecare pereche generează un nod în polinomul produs
-gradul noului nod va fi suma gradelor nodurilor din pereche
-coeficientul noului nod va fi produsul coeficienţilor termenilor din
pereche
-se elimină nodurile din lista de termeni prin păstrarea fiecărui grad o
singură dată astfel: dacă există două noduri cu acelaşi grad unul din
ele va fi eliminat, iar coeficientul celuilalt va avea valoarea sumei
coeficienţilor celor doi termeni.
Valoarea unui polinom se va calcula prin parcurgerea listei şi
adăugând la valoare produsul dintre coeficient şi valoarea dată la
puterea gradului din nod.
40
prima listă şi pentru fiecare nod se verifică dacă elementul se află şi în
cea de-a doua listă, dacă da atunci se adaugă în cea de-a treia listă.
Implementare Pascal:
type lista=^nod;
nod = record inf:integer; urm:lista end;
var q,cap1,cap2,cap3:lista;
gasit:boolean;
procedure creare(var cap:lista);
var n,i:integer;
nou,q:lista;
begin
write('nr elem'); read(n); new(cap); read(cap^.inf);
cap^.urm:=nil;
for i:=2 to n do begin
new(nou); read(nou^.inf); nou^.urm:=nil; q:=cap;
while q^.urm<>nil do q:=q^.urm;
q^.urm:=nou
end
end;
procedure diferenta(cap1,cap2:lista);
var x:integer;
q2:lista;
begin
q:=cap1;
while q<>nil do begin
x:=q^.inf; gasit:=false; q2:=cap2;
while q2<>nil do begin
if q2^.inf=x then gasit:=true; q2:=q2^.urm
end;
if not gasit then write(x, ' '); q:=q^.urm
end
end;
procedure afisare(cap:lista);
var q:lista;
begin
q:=cap;
while q<>nil do begin write(q^.inf,' '); q:=q^.urm end;
writeln;
end;
41
procedure intersectie(cap1,cap2:lista; var cap3:lista);
var q,q2,nou,q3:lista;
x:integer;
begin
q:=cap1;
while q<>nil do begin
x:=q^.inf; gasit:=false; q2:=cap2;
while q2<>nil do begin
if q2^.inf=x then gasit:=true;
q2:=q2^.urm;
end;
if gasit then if cap3=nil then
begin new(cap3); cap3^.inf:=x; cap3^.urm:=nil end
else begin
new(nou); nou^.inf:=x ; nou^.urm:=nil; q3:=cap3;
while q3^.urm<> nil do q3:=q3^.urm;
q3^.urm:=nou
end;
q:=q^.urm
end
end;
begin
creare(cap1); creare(cap2); afisare(cap1); afisare(cap2);
diferenta(cap1,cap2);
writeln; diferenta(cap2, cap1);
writeln('intersectie'); intersectie(cap1,cap2,cap3); afisare(cap3);
end.
Rezolvare:
Paşii: -crearea unui nod nou
-dacă informaţia care se adaugă este mai mică decât informaţia
din capul listei atunci se inserează în faţa primului nod
-altfel se parcurge lista până la primul nod a cărei informaţie este
mai mare decât informaţia noului nod şi se inserează.
42
Implementare C:
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
typedef struct nod { int inf; struct nod*urm;} lista;
lista *prim;
lista *creare(void);
void parcurgere(lista *p);
void main(){
lista *prim;
prim=creare();
parcurgere(prim);
}
lista *creare(){
int n,inf; lista *prim,*p,*q,*nou;
printf("nr. de elemente");scanf("%d",&n);
prim=NULL;
for(int i=1;i<=n;i++){
printf("informatia nod");scanf("%d",&inf);
nou=(lista *)malloc(sizeof(lista));
nou->inf=inf;
if (prim==NULL){
prim=nou;prim->urm=NULL;
}
else if (prim->inf>inf){
nou->urm=prim;prim=nou;
}
else {
p=q=prim;
while(p&&p->inf<inf){q=p; p=p->urm;}
if (p) {q->urm=nou; nou->urm=p;}
else{q->urm=nou; nou->urm=NULL;}
}
}
return prim;
}
void parcurgere(lista *p){ lista *q;
for (q=p;q;q=q->urm) printf("%d ",q->inf);
}
43
Exerciţiu: Să se implementeze aplicaţia de mai sus în Pascal.
Rezolvare:
Se va parcurge simultan cele două liste urmând ca introducerea unui
nod în lista finală să fie făcută din lista care are valoarea informaţiei
din nod mai mică.
Implementare C:
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
typedef struct nod {int inf; struct nod*urm;}lista;
lista *inter(lista *prim1, lista*prim2){
lista *prim,*ultim;
if (prim1->inf>prim2->inf){
prim=prim2;prim2=prim2->urm;
}
else {
prim=prim1;
prim1=prim1->urm;
}
ultim=prim;
while(prim1&&prim2)
if (prim1->inf>prim2->inf){
ultim->urm=prim2;
ultim=prim2;
prim2=prim2->urm;
}
else {ultim->urm=prim1;
ultim=prim1;
prim1=prim1->urm;
}
if (prim1) ultim->urm=prim1; else ultim->urm=prim2;
return prim;
}
lista *creare(void);
void parcurgere(lista *p);
44
void main(){
lista *prim1,*prim2,*prim;
prim1=creare();
prim2=creare();
/* parcurgere(prim1) */;
prim=inter(prim1,prim2);
parcurgere(prim1);
}
lista *creare(){
int n,inf; lista *prim,*p,*q,*nou;
printf("nr. de elemente");scanf("%d",&n);
prim=NULL;
for(int i=1;i<=n;i++){
printf("informatia nod");scanf("%d",&inf);;
nou=(lista *)malloc(sizeof(lista));
nou->inf=inf;
if (prim==NULL){
prim=nou;
prim->urm=NULL;
}
else if (prim->inf>inf){
nou->urm=prim;prim=nou;
}
else {
p=q=prim;
while(p&&p->inf<inf){q=p;p=p->urm;}
if(p) {q->urm=nou;nou->urm=p;}
else {
q->urm=nou;nou->urm=NULL;
}
}
}
return prim;
}
void parcurgere(lista *p){ lista *q;
for (q=p;q;q=q->urm) printf("%d ",q->inf);
}
45
2.2. Liste dublu înlănţuite
Pentru liste duble create dinamic modul de definire a unui nod este:
Limbajul Pascal typedef struct nod{
type lista=^nod; inf tip;
nod=record struct nod *urm;
inf:tip; struct nod *ant;
urm, ant:lista; }lista;
end;
Probleme rezolvate
47
if i=k then begin
q:=p; p^.ant^.urm:=p^.urm;
p^.urm^.ant:=p^.ant; dispose(q);
end
else begin write('nu exista'); readln end
end
end;
procedure parcurgere(var cap:lista);
var q:lista;
begin
q:=cap;
while q<>nil do begin write(q^.inf, ' '); q:=q^.urm end;
readln
end;
procedure parcurgere_inv(var cap:lista);
var q:lista;
begin
q:=cap;
while q^.urm<>nil do q:=q^.urm;
while q<>nil do begin write(q^.inf, ' '); q:=q^.ant end;
readln;
end;
begin
while x<> 7 do begin
writeln('1.creare'); writeln('2.adaugare');
writeln('3.inserare'); writeln('4.stergere');
writeln('5.parcurgere'); writeln('6.parcurgere_inv');
writeln('7.iesire');
readln(x);
case x of
1:creare(cap);
2:adaugare(cap);
3:inserare(cap);
4:stergere(cap);
5:parcurgere(cap);
6:parcurgere_inv(cap);
end
end
end.
48
2. Crearea şi parcurgerea listei dublu înlănţuite în limbajul C:
#include<stdio.h>
#include<stdlib.h>
typedef struct nod{int inf; struct nod*urm,*ant; } lista;
lista*prim ,*ultim;
void creare(int n);
void parcurg(lista*prim);
void parcurg1(lista*ultim);
void main(){
int n;
printf("numarul de elemente:");scanf("%d",&n);
creare(n);
puts("\n Parcurgere directa");parcurg(prim);
puts("\n Parcurgere indirecta");parcurg1(ultim);
}
void creare(int n){
int i;
lista *p;
prim=(lista*)malloc(sizeof(lista));
printf("informatia primului nod"); scanf("%d",&prim->inf);
prim->urm=prim->ant=NULL;
ultim=prim;
for(i=2;i<=n;i++){
p=(lista*)malloc(sizeof(lista));
printf("inf=");scanf("%d",&p->inf);
p->ant=ultim;ultim->urm=p;
p->urm=NULL;
ultim=p;
}
}
void parcurg(lista*p){
if (p){
printf("%d ",p->inf); parcurg(p->urm);
}
}
void parcurg1(lista *p){
lista *q;
for (q=p;q;q=q->ant) printf("%d ",q->inf);
}
49
2.3. Liste circulare
După numărul de legături, listele circulare se împart în: liste simple şi
liste duble. Listele circulare simple sunt liste simple care au în plus
propietatea că valoarea câmpului următor a ultimului nod este adresa
capului listei. Listele circulare duble sunt liste duble care au
propietatea că legătura următor a celui de-al doilea cap este primul
cap şi legătura anterior a primului cap este al doilea cap.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
typedef struct nod{ int inf; struct nod *urm;}lista;
void main(){
lista *prim,*p,*q;
int i,n;
/*crearea listei circulare*/
printf("inf primului nod");
prim=(lista*)malloc(sizeof(lista));
scanf("%d",&prim->inf);prim->urm=NULL;
p=prim;
printf("nr de elemente");scanf("%d",&n);
for (i=2;i<=n;i++){
q=(lista*)malloc(sizeof(lista));
printf("inf=");scanf("%d",&q->inf);
p->urm=q;p=q;
}
p->urm=prim;
/*parcurgerea listei*/
printf("%d ",prim->inf);
for (q=prim->urm;q!=prim;q=q->urm)
printf("%d ",q->inf);
}
51
Implementarea C (Lista circulară este dublă).
#include <stdio.h>
#include<stdlib.h>
typedef struct nod{int inf; struct nod *urm,*ant; }lista;
lista *prim,*p,*q;
void creare(void);
void parcurgere(void);
int n,m,i,k;
void main(){
creare();
printf("pasul de numarare");scanf("%d",&m);
parcurgere();
while (p!=p->ant){
for( i=1;i<m;i++)p=p->urm;
printf("%d ",p->inf);
p->ant->urm=p->urm;
p->urm->ant=p->ant;
q=p;p=p->urm;free(q);
}
printf("%d",p->inf);
}
void parcurgere(){
for (p=prim,i=1;i<=n;i++,p=p->urm) printf("%d",p->inf);
/* p=p->urm;*/
}
void creare(){
printf("nr. de copii");scanf("%d",&n);
prim=(lista*)malloc(sizeof(lista));prim->inf=1;
prim->urm=prim->ant=NULL; p=prim;
for (i=2; i<=n; i++){
q=(lista*)malloc(sizeof(lista));
q->inf=i;
p->urm=q;
q->ant=p;
p=q;
}
q->urm=prim;prim->ant=q;
}
52
2.4. Stive
O stivă (stack) este o listă liniară cu proprietatea că operaţiile de
inserare/extragere a nodurilor se fac în/din vârful listei. Ultimul nod
inserat va fi şi primul şters, stivele se mai numesc şi liste LIFO (eng.
Last In First Out) sau liste pushdown.
push
pop
Rezolvare:
Implementarea Pascal:
type stiva=^nod;
nod=record inf:integer; urm:stiva end;
var cap:stiva;
x:integer;
procedure adauga(var cap:stiva);
var nou:stiva;
begin
new(nou);
writeln('Ce sa adaug? ');
readln(nou^.inf);
nou^.urm:=nil;
if cap=nil then cap:=nou
else begin
nou^.urm:=cap;
cap:=nou;
end;
end;
procedure sterge(var cap:stiva);
var q:stiva;
begin
if cap=nil then writeln('Stiva vida')
else begin
q:=cap;
cap:=cap^.urm;
dispose(q)
end;
end;
procedure parcurgere(cap:stiva);
var q:stiva;
begin
q:=cap;
while q<> nil do begin
writeln('|',q^.inf,'|'); q:=q^.urm end;
writeln('___')
end;
54
begin
while x<> 4 do begin
writeln('1.Adaugare');
writeln('2.Stergere');
writeln('3.Listare');
writeln('4.Iesire');
writeln('Dati optiunea');
readln(x);
case x of
1:adauga(cap);
2:sterge(cap);
3:parcurgere(cap)
end
end
end.
55
atunci când coada este vidă. Iniţial, avem p= u= 0. Inserarea şi
ştergerea (extragerea) unui nod necesită timp constant.
Implementarea Pascal:
TYPE coada=array[1..50] of integer;
var c:coada; p,n,u,o,x:integer;
procedure adaugare(var c:coada; var p,u:integer;x:integer);
begin
if p<>(u mod n)+1 then
begin c[u]:=x; u:=u mod n +1 end
else writeln('coada plina');
end;
56
procedure stergere(var c:coada; var p,u,x:integer);
begin
if p<>u then begin x:=c[p]; p:=p mod n+1 end
else writeln('coada goala');
end;
procedure listare(c:coada;p,u:integer);
var i:integer;
begin
if p=u then writeln('coada goala')
else begin
i:=p;
while i<>u do begin write(c[i],' '); i:=i mod n+1 end;
end;
end;
begin
writeln('nr max de elem');
read(n);n:=n+1;
p:=1;u:=1;
repeat
writeln('1..adaugare');
writeln('2..stergere');
writeln('3..listare');
write('citeste optiunea');readln(o);
case o of
1: begin
write('introduceti numarul adaugat');readln(x);
adaugare(c,p,u,x);
end;
2: begin
stergere(c,p,u,x);
if p<>u then writeln(x);
end;
3: listare(c,p,u);
end;
writeln;
until o=4;
end.
57
Problemă rezolvată: Să se creeze un program care să conţină un
meniu cu operaţii asupra unei cozi alocate dinamic.
Rezolvare:
Implementarea în limbajul C++:
#include <conio.h>
#include<stdlib.h>
#include<iostream.h> // intrări-ieşiri în C++
typedef struct nod {int inf; struct nod *urm; }lista;
void adaug(lista* &prim, int x){
lista *nou, *p;
nou=new lista; // crearea unui nod în C++
nou->inf=x;nou->urm=NULL;
if (prim==NULL) prim=nou;
else {
nou->urm=prim; prim=nou;
}
}
lista * creare(){
int n,x;
lista*prim;
prim=NULL;
clrscr();
cout<<"\n nr. de noduri=";cin>>n;
for (int i=0;i<n;i++){
cout<<"inf "<<(i+1)<<":";
cin>>x;
adaug(prim,x);
}
return prim;
}
void parcurgere(lista *prim){
lista *p;
clrscr();
p=prim;
while (p!=NULL){
cout<<p->inf<<' '; p=p->urm;}
cout<<'\n';
getch();
}
58
void sterg(lista *&prim){
lista *p;
if (prim==NULL) cout<<"coada este vida";
else {
p=prim;
while (p->urm->urm!=NULL){p=p->urm;}
delete p->urm; p->urm=NULL;
}
}
void main(){
lista *prim=NULL;
int opt,x;
do{
clrscr();
cout<<"Coada\n";
cout<<"1.Creare coada\n";
cout<<"2.Adaugare\n";
cout<<"3.Stergere\n";
cout<<"4.Parcurgere\n";
cout <<"5.Iesire\n";
do{
cout<<"optiunea";cin >>opt;
}while (opt<1&&opt>5);
switch(opt){
case 1:{prim=creare();break;}
case 2:{
clrscr();cout<<"inf. noua:";cin>>x;
adaug(prim,x);break;
}
case 3:{
clrscr();
cout<<"inf stearsa="<<(prim->inf);
sterg(prim);break;
}
case 4:{
parcurgere(prim); getch();break;
}
}
}while (opt!=5);
}
59
Exerciţiu: Să se realizeze programul în Pascal corespunzător
aplicaţiei de mai sus.
Probleme propuse:
1. Fiind dată o listă simplu înlănţuită având informaţii numere întregi
să se elimine numerele negative.
2. Să se realizeze interclasarea a n liste simplu înlănţuite ordonate
crescător.
3. Fiind date două liste simple cu informaţii de tip întreg, să se
realizeze subprograme pentru următoarele operaţii: intersecţia,
reuniunea, diferenţa şi diferenţa simetrică a elementelor celor
două liste.
4. Să se scrie un program care citeşte cuvintele dintr-un fişier text
in.txt, cuvintele sunt separate prin spaţii şi afişează numărul de
apariţii al fiecărui cuvânt din fişier. Se vor folosi liste simplu
înlănţuite.
5. Să se elimine dintr-o listă simplu înlănţuită toate nodurile care au
o informaţie dată.
6. Să se realizeze operaţii cu matrici rare folosind alocarea dinamica.
7. Fiind dată o listă dublă, să se separe în două liste elementele de pe
poziţii pare de elementele de pe poziţii impare.
8. Fiind dată o listă dublă cu informaţii de tip şir de caractere, să se
facă ordonarea elementelor listei.
9. Fiind dată o listă dublă cu informaţii de tip întreg să se
construiască o listă dublă numai cu elemente prime.
10. Pe o tijă sunt n bile colorate cu cel mult k culori, fiecare bilă
având o etichetă cu un număr de la 1 la n. Să se mute bilele pe alte
k tije, pe fiecare punând numai bile din aceeaşi culoare. Să se
afişeze bilele de pe fiecare din cele k tije, folosind structuri
dinamice.
Indicaţie: Tija iniţială reprezintă o stivă, informaţia dintr-un nod va fi
compusă din numărul bilei şi numărul culorii. Se va parcurge stiva şi
se adaugă în stiva corespunzătoare culorii, apoi se şterge din stiva
iniţială. Se va lucra cu un vector de stive pentru cele k tije.
60
determine un traseu posibil de parcurgere astfel încât să nu rămână
în pană ştiind că în fiecare oraş există o staţie de benzină cu o
cantitate de benzină suficientă, iar maşina consuma c litri la 100
de kilometri.
13. Fiind dată o listă circulară dublă, să se facă un subprogram de
inserare a unui element pe o poziţie dată.
14. Să se realizeze un subprogram care şterge elementele egale cu
zero dintr-o listă circulară.
15. Să se creeze o listă de liste, să se parcurgă şi să se şteargă.
16. Să se scrie un program care citeşte cuvintele dintr-un text şi
afişează numărul de apariţii al fiecărui cuvânt din textul respectiv.
17. Să se scrie un program care citeşte cuvintele dintr-un text şi scrie
numărul de apariţie al fiecărui cuvânt, în ordinea alfabetică a
cuvintelor respective.
18. Într-o gară se consideră un tren de marfă ale cărui vagoane sunt
inventariate într-o listă. Lista conţine, pentru fiecare vagon,
următoarele date: codul vagonului, codul conţinutului vagonului,
adresa expeditorului, adresa destinatarului. Deoarece în gară se
inversează poziţia vagoanelor, se cere listarea datelor despre
vagoanele respective în noua lor ordine.
Indicaţie: se creează o stivă în care se păstrează datele fiecărui vagon.
Datele corespunzătoare unui vagon constituie un element al stivei,
adică un nod al listei simplu înlănţuite. După ce datele au fost puse în
stivă, ele se scot de acolo şi se listează.
61
20. Să se realizeze un program care implementează subprograme
pentru crearea şi exploatarea unei cozi duble.
21. Se dă o matrice rară memorată într-o listă. Se cere:
a) să se afişeze toate elementele diferite de zero de pe diagonala
principală, secundară;
b) să se afişeze pe ecran matricea sub forma obişnuită, fără
reconstituirea ei în memorie.
2.6. Grafuri
Noţiuni introductive
Un graf este o pereche G = <V, M>, unde V este o mulţime de vârfuri,
iar M = VxV este o mulţime de muchii. O muchie de la vârful a la
vârful b este notată cu perechea ordonată (a, b), dacă graful este
orientat, şi cu mulţimea {a, b}, dacă graful este neorientat. Două
vârfuri unite printr-o muchie se numesc adiacente. Un drum este o
succesiune de muchii de forma (a1, a2), (a2, a3), ..., (an-1, an) sau de
forma {a1, a2}, {a2, a3}, ..., {an-1, an} după cum graful este orientat sau
neorientat. Lungimea drumului este egală cu numărul muchiilor care îl
constituie. Un drum simplu este un drum în care nici un vârf nu se
repetă. Un ciclu este un drum care este simplu, cu excepţia primului şi
ultimului vârf, care coincid. Un graf aciclic este un graf fără cicluri.
Un subgraf al lui G este un graf <V', M'>, unde V' ⊆ V, iar M' este
formată din muchiile din M care unesc vârfuri din V'. Un graf parţial
este un graf <V, M">, unde M" ⊆ M.
Un graf neorientat este conex, dacă între oricare două vârfuri
există un drum. Pentru grafuri orientate, această noţiune este întărită:
un graf orientat este tare conex, dacă între oricare două vârfuri i si j
există un drum de la i la j şi un drum de la j la i.
În cazul unui graf neconex, se pune problema determinarii
componentelor sale conexe. O componenta conexă este un subgraf
conex maximal, adică un subgraf conex în care nici un vârf din
subgraf nu este unit cu unul din afară printr-o muchie a grafului iniţial.
Împărţirea unui graf G = <V, M> în componentele sale conexe
determina o partiţie a lui V şi una a lui M.
Un arbore este un graf neorientat aciclic conex. Sau, echivalent,
un arbore este un graf neorientat în care există exact un drum între
oricare două vârfuri. Un graf parţial care este arbore se numeşte
arbore partial. Vârfurilor unui graf li se pot ataşa informaţii numite
62
uneori valori, iar muchiilor li se pot ataşa informaţii numite uneori
lungimi sau costuri.
8 0 1 2 3 4 5 6 7 8
0 0 0 1 0 0 1 0 0 0
7 1 0 0 0 0 0 0 1 0 0
2 0 0 0 0 0 0 1 0 0
5 3 3 0 0 0 0 1 0 0 0 0
4 0 0 0 0 0 1 0 0 0
2 0 4 5 0 0 0 1 0 0 0 1 0
6 0 0 0 0 0 0 0 0 0
6 1 7 0 0 1 0 0 0 0 0 1
8 0 0 0 0 0 0 0 0 0
b) Listele de muchii
Această metodă de memorare presupune reţinerea unei matrice cu 2
linii şi m coloane, pe fiecare coloană fiind reţinute două extremităţi ale
unei muchii. Aceasta reprezentare este eficientă atunci când avem de
examinat toate muchiile grafului.
63
Listele de muchii sunt folosite în cazul algoritmilor care prelucrează
secvenţial muchiile, cum ar fi de exemplu algoritmul Kruskal de aflare
a arborelui parţial de cost minim în cazul grafurilor rare (cu număr
mic de muchii).
c) Listele de vecini.
Prin liste de vecini (adiacenţă) se realizează ataşarea la fiecare vârf i a
listei de vârfuri adiacente lui (pentru grafuri orientate, este necesar ca
muchia să plece din i). Într-un graf cu m muchii, suma lungimilor
listelor de adiacenţă este 2m, dacă graful este neorientat, respectiv m,
dacă graful este orientat. Dacă numărul muchiilor în graf este mic,
această reprezentare este preferabilă din punct de vedere al memoriei
necesare. Este posibil să examinăm toţi vecinii unui vârf dat, în medie,
în mai puţin de n operaţii. Pe de altă parte, pentru a determina dacă
două vârfuri i şi j sunt adiacente, trebuie să analizăm lista de adiacenţă
a lui i (şi, posibil, lista de adiacenţă a lui j), ceea ce este mai puţin
eficient decât consultarea unei valori logice în matricea de adiacenţă.
Listele de vecini sunt cele mai recomandate în tratarea algoritmilor din
teoria grafurilor din două motive principale:
1. spatiul folosit este gestionat dinamic, putându-se memora astfel
grafuri de dimensiuni mari;
2. complexitatea optimă pentru majoritatea algoritmilor fundamen-
tali din teoria grafurilor (parcurgeri, conexitate, muchii şi puncte
critice, algoritmi de drum minim etc.) este obţinută numai folosind
liste de vecini.
Există două modalităţi de implementare a listelor de vecini.
a) Prima dintre ele foloseşte o matrice T cu 2 linii şi 2m coloane şi
un vector C cu n elemente care reţine pentru fiecare nod indicele
coloanei din T pe care este memorat primul element al listei
nodului respectiv (sau 0 dacă vârful respectiv nu are vecini). Apoi,
pentru o anumită coloană i din T, T(i,1) reţine un element din lista
curentă, iar T(i,2) reţine coloana pe care se găseşte următorul
element din lista respectivă sau 0 dacă lista s-a terminat.
b) Cea de-a doua implementare foloseşte pentru fiecare nod o listă
simplu înlănţuită memorată în heap. Pentru fiecare listă este
suficient să păstrăm o singură santinelă (cea de început a listei),
introducerea vârfurilor făcându-se mereu la începutul listei
(deoarece ordinea vârfurilor în listă nu contează).
64
Exemplu:
8
0 2 5
1 6
7 2 6
3 4
5 3 4 5
5 3 7
2 0 4 6
7 2 8
8
6 1
Parcurgerea grafurilor
Parcurgerea unui graf presupune examinarea în vederea prelucrării
tuturor vârfurilor acelui graf într-o anumită ordine, ordine care să
permită prelucrarea optimă a informaţiilor ataşate grafului.
a) Parcurgerea DF (parcurgerea în adâncime)
Parcurgerea DF (Depth First) presupune ca dintr-un anumit nod v,
parcurgerea să fie continuată cu primul vecin al nodului v nevizitat
încă. Parcurgerea în adâncime a fost formulată cu mult timp în urmă
ca o tehnică de explorare a unui labirint. O persoană care caută ceva
într-un labirint şi aplică această tehnică are avantajul ca “următorul loc
în care caută” este mereu foarte aproape.
Parcurgerea vârfurilor în adâncime se
1 2 face în ordinea: 1 3 4 5 2 6
3
Cel mai cunoscut mod de imple-
mentare a parcurgerii DF se realizează
cu ajutorul unei funcţii recursive, dar
există şi cazuri în care este recomandată
4
o implementare nerecursivă.
6
5 Implementarea acestei metode se
face folosind o stivă. Aceasta este iniţia-
65
lizată cu un nod oarecare al grafului. La fiecare pas, se ia primul vecin
nevizitat al nodului din vârful stivei şi se adaugă în stivă dacă nu mai
există se coboară în stivă.
Algoritmul recursiv:
procedure DF(G)
for fiecare v ∈ V do marca[v] ← nevizitat
for fiecare v ∈ V do
if marca[v] = nevizitat then ad(v)
procedure ad(v)
{varful v nu a fost vizitat}
marca[v] ← vizitat
for fiecare virf w adiacent lui v do
if marca[w] = nevizitat then ad(w)
Algoritmul iterativ:
procedure iterad(v)
S ← stiva vida
marca[v] ← vizitat
push(v, S)
while S nu este vida do
while exista un varf w adiacent lui ftop(S)
astfel incat marca[w] = nevizitat do
marca[w] ← vizitat
push(w, S)
pop(S)
Parcurgere_BF(nod start)
Coada ← start
Vizitat(start) ←adevărat
cât timp coada nu este vidă
ic ←nodul de la începutul cozii
adaugă toti vecinii nevizitati ai lui ic în coadă
Vizitat(i) ← adevărat, unde i este un vecin nevizitat al
nodului ic
procedure lat(v)
C ← coada vida
marca[v] ← vizitat
insert-queue(v, C)
67
while C nu este vida do
u ← delete-queue(C)
for fiecare virf w adiacent lui u do
if marca[w] = nevizitat then marca[w] ← vizitat
insert-queue(w, C)
Pentru compararea celor două metode apelăm procedurile iterad şi lat
din procedura parcurgere(G)
procedure parcurge(G)
for fiecare v ← V do marca[v] ← nevizitat
for fiecare v ← V do
if marca[v] = nevizitat then {iterad sau lat} (v)
S = {0}
for i = 1 to n D[i] = M[1][i]
68
for i = 1 to n-2
caut cel mai mic D[v] pentru fiecare v ∉ S
S = S ∪ {v}
for toate vârfurile u ∉ S
if (D[u] > D[v] + M[v][u]) then D[u] = D[v] + M[v][u]
Implementare în C:
#include <stdio.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
#define MAXN 20
int setupDijkstra
(int *nod_p, int a[MAXN][MAXN], int *startnod_p);
void doDijkstra
(int nod, int a[MAXN][MAXN], int startnod);
void traceinfo
(int S[MAXN], int D[MAXN], int nod);
int main(){
int nod, startnod;
int a[MAXN][MAXN];
printf("Algoritmul lui Dijkstra\n");
if (setupDijkstra(&nod, a, &startnod)) return 1;
doDijkstra(nod, a, startnod);
return 0;
}
int setupDijkstra
(int *nod_p, int a[MAXN][MAXN], int *startnod_p){
int i, j;
do{
printf("Introduceti 0 pentru a specifica graful,sau 1 pentru exemple ");
scanf("%d", &i);
}while ((i < 0) || (i > 1));
if (i == 1){
*nod_p = 5;
for (i=0; i<*nod_p; i++)
for (j=0; j<*nod_p; j++) a[i][j]=99;
a[0][1]=a[1][0]=1; a[1][2]=a[2][1]=3; a[0][3]=a[3][0]=2;
a[3][4]=a[4][3]=4; a[1][4]=a[4][1]=2; a[2][4]=a[4][2]=1;
69
printf("A Matrix: a b c d e\n");
for (i=0; i<*nod_p; i++){
printf(" %c", 'a'+i);
for (j=0; j<*nod_p; j++)
printf("%3d", a[i][j]);
printf("\n");
}
*startnod_p = 0;
}
else {
printf("Enter number of nod (1-%d) ", MAXN);
if (scanf("%d", nod_p) != 1) return 1;
if ( (*nod_p < 1) || (*nod_p > MAXN) ) return 2;
for (i=0; i<*nod_p; i++){
printf("Introduceti randul %d matricii: ", i+1);
for (j=0; j<*nod_p; j++)
if (scanf("%d", &a[i][j]) != 1) return 3;
}
printf("introduceti nodul (1-%d) ", *nod_p);
if (scanf("%d", &i) != 1) return 4;
if ( (i < 1) || (i > *nod_p) ) return 5;
*startnod_p = i-1;
}
return 0;
}
void doDijkstra
(int nod, int a[MAXN][MAXN], int startnod){
int S[MAXN];
int D[MAXN]; int i, j, urmnod, mic;
/* initializare */
for (i=0; i<nod; i++) S[i] = FALSE;
S[startnod] = TRUE;
for (i=0; i<nod; i++) {D[i] = a[startnod][i]; }
printf("Initializare\n"); traceinfo(S, D, nod);
for (i=1; i<nod; i++){
urmnod = 999; mic = 999;
for (j=0; j<nod; j++){
if (!S[j]){
if (D[j] < mic){ mic = D[j];urmnod = j;}
}}
70
if (urmnod >= nod) return;
// printf(" D[%c]=%2d, ", 'a'+urmnod, mic);
printf("adauga nodul %c to S\n", 'a'+urmnod);
S[urmnod] = TRUE;
for (j=0; j<nod; j++){
if (!S[j]){
/* printf("Compara D[%c]=%2d si D[%c]+M[%c][%c]=%2d, ", \
'a'+j, D[j], 'a'+urmnod, 'a'+urmnod, 'a'+j, \
D[urmnod]+a[urmnod][j]);
*/
if (D[j] > D[urmnod] + a[urmnod][j]){
D[j] = D[urmnod] + a[urmnod][j];
/*printf("D[%c] schimba %2d\n", 'a'+j, D[j]); */
}
else
/* printf("nu schimba\n"); */
}
}
traceinfo(S, D, nod);
}
}
void traceinfo(int S[MAXN], int D[MAXN], int nod){
int i;
printf(" S = {");
for (i=0; i<nod; i++) if (S[i]) printf("%c", 'a' + i);
printf("}\n");
printf(" D = ");
for (i=0; i<nod; i++) printf("%3d", D[i]);
printf("\n");
}
Implementare în C:
#include <stdio.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
#define MAXN 26
#define INFINIT 999
int setupBellman(int *nod_p, int a[MAXN][MAXN], int *start_p);
int doBellman(int nod, int a[MAXN][MAXN], int start);
void traceinfo(int D[MAXN], int nod);
int main(){
int nod, start; int a[MAXN][MAXN];
printf("Algoritmul lui Bellman-Ford\n");
if (setupBellman(&nod, a, &start)) return 1;
if (doBellman(nod, a, start)){
printf(" Ciclu negativ\n"); return 2;}
return 0;}
72
int setupBellman
(int *nod_p, int a[MAXN][MAXN], int *start_p){
int i, j;
do{
printf("Introduceti 0 pentru graf, or 1 pentru exemple ");
scanf("%d", &i);
}while ((i < 0) || (i > 1));
if (i == 1){
*nod_p = 5;
for (i=0; i<*nod_p; i++) for (j=0; j<*nod_p; j++) a[i][j]=99;
a[0][1]=a[1][0]=1; a[1][2]=a[2][1]=3; a[0][3]=a[3][0]=2;
a[3][4]=a[4][3]=4; a[1][4]=a[4][1]=2; a[2][4]=a[4][2]=1;
printf("A Matrix: a b c d e\n");
for (i=0; i<*nod_p; i++){
printf(" %c", 'a'+i);
for (j=0; j<*nod_p; j++) printf("%3d", a[i][j]);
printf("\n");
}
*start_p = 0;
}
else{
printf("Introduceti nr. noduri (1-%d) ", MAXN);
if (scanf("%d", nod_p) != 1) return 1;
if ( (*nod_p < 1) || (*nod_p > MAXN) ) return 2;
for (i=0; i<*nod_p; i++){
printf("Introduceti randul %d al matricii: ", i+1);
for (j=0; j<*nod_p; j++)
if (scanf("%d", &a[i][j]) != 1) return 3;
}
printf("Introduceti nodul de start (1-%d) ", *nod_p);
if (scanf("%d", &i) != 1) return 4;
if ( (i < 1) || (i > *nod_p) ) return 5;
*start_p = i-1;
}
return 0;
}
73
for (i=0; i<nod; i++){
if (i == start) D[i] = 0; else D[i] = INFINIT;
}
printf("Initializared\n"); traceinfo(D, nod);
for (i=1; i<nod; i++){
for (u=0; u<nod; u++){
for (v=0; v<nod; v++){
if (a[u][v] < 99){
/*
printf("Compara D[%c]=%3d si D[%c]+M[%c][%c]=%3d, ",\
'a'+v, D[v], 'a'+u, 'a'+u, 'a'+v, D[u]+a[u][v]);
*/
if (D[v] > D[u] + a[u][v]){
D[v] = D[u] + a[u][v];
printf("D[%c] schimba to %2d\n", 'a'+v, D[v]);
}
else printf("nu schimba\n");
}
}
}
traceinfo(D, nod);
}
for (u=0; u<nod; u++){
for (v=0; v<nod; v++){
if (a[u][v] < 99){
/*printf("Compara D[%c]=%3d and D[%c]+M[%c][%c]=%3d, ",\
'a'+v, D[v], 'a'+u, 'a'+u, 'a'+v, D[u]+a[u][v]);
*/
if (D[v] > D[u] + a[u][v]) return 1;
else printf("nu exista ciclu negativ\n");
}
}
}
return 0;
}
void traceinfo(int D[MAXN], int nod){
int i;
printf(" D = ");
for (i=0; i<nod; i++) printf("%4d", D[i]);
printf("\n");}
74
Probleme rezolvate
Exerciţiu:
Implementaţi în lumbajul C aplicaţia de mai sus folosind funcţia Df
(iterativă) de mai jos.
75
s[1]=x;viz[x]=1;printf("%d ",x);
while (k>=1) /*cat timp stiva este nevida */ {
y=s[k];gasit=0;
for(i=1;i<=n;i++)
if (viz[i]==0&&a[y][i]==1) {
printf("%d ",i); //vecin nevizitat
viz[i]=1;
s[++k]=i;
gasit=1;
break;
}
if (!gasit) k--;
}
}
81
for i:= 1 to n do begin
for j:=1 to n do write(c[i,j]:4);
writeln
end;
write('Dati doua noduri'); readln(x,y);
writeln('costul minim= ', c[x,y], ' drumurile minime=' );
for x:=1 to n do for y:=1 to n do
begin
writeln('drum de la ',x,'la ',y);
if c[x,y]=maxint then write('nu exista')
else begin
nr:=1;v[1]:=y;
drum(x,y)
end
end
end.
Exerciţiu: Să se implementeze algoritmul Roy-Floyd în limbajul C.
83
begin
assign(f,'in.txt');reset(f);
readln(f,n);
for i:=1 to n do begin
while not eoln(f) do begin
read(f,x);
adaugare(bl[i],x)
end;
readln(f);
end;
writeln;
df(1);
complet:=true;
for i:=1 to n do if numarare(bl[i])<>n-1 then complet:=false;
if complet then write('complet') else write ('incomplet');
end.
Exerciţiu: Să se implementeze aplicaţia de mai sus în limbajul c.
R2.6.7. Fiind dat un graf, să se verifice dacă este aciclic.
Rezolvare:
Un graf este aciclic dacă este fără cicluri. Presupunem că fiecare nod
face parte dintr-o componentă conexă. Se ia fiecare muchie şi dacă
extremităţile sunt în aceeaşi componentă conexă atunci adăugând
aceea muchie se formează ciclu; dacă nu sunt în aceeaşi componentă
conexă toate nodurile care sunt în aceeaşi componentă cu extremitatea
a doua trec în componenta conexă a extremităţii 1.
Implementare Pascal:
Var f:text;
a:array[1..1000]of integer; n:integer; nume:string;
procedure ciclic;
var i,j,k:integer;
begin
writeln('Care este numele fisierului de intrare ?');
readln(nume);
assign(f,nume); reset(f);
readln(f,n);
for i:=1 to n do a[i]:=i;
while not seekeoln(f) do
begin
readln(f,i,j);
84
if a[i]=a[j] then
begin
writeln('Graful din fisierul ',nume,' contine cel putin un ciclu');
close(f); halt;
end;
for k:=1 to n do if a[k]=a[j] then a[k]:=a[i];
end;
writeln('Graful din fisierul ',nume,' nu contine cicluri');
close(f);
end;
begin
ciclic
end.
Implementare C:
#include <stdlib.h>
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
FILE *f;
int n,a[10];
void ciclic(){
int i,j,k;
fscanf(f,"%d",&n);
for(i=1;i<=n;i++)a[i]=i;
fscanf(f,"%d %d",&i,&j);
if (a[i]==a[j]) {
cout<<"contine ciclu";
fclose(f);
exit(1);
}
for (k=1; k<=n; k++){
if (a[k]==a[j]) a[k]=a[i];
}
cout<<"nu contine cicluri";
}
void main(void){
f=fopen("in.txt","r");clrscr();
ciclic();
}
85
R2.6.8. Se dă un graf şi un nod - considerat ca nodul nr. 1; se
cere să se determine toate nodurile accesibile din acest nod.
Rezolvare:
Implementare Pascal:
var
a: array[1..20,1..20] of integer; {matricea de adiacenta}
c: array[1..20] of integer;
{vectorul unde pastram nodurile accesibile}
n,i,j,k,p:integer; gasit:boolean;
begin
write('dati numarul de noduri; n=');readln(n);
writeln('dati matricea de adiacenta:');
for i:=1 to n do for j:=1 to n do read(a[i,j]);
c[1]:=1; k:=1; gasit:=true; i:=1;
while i<=k do begin
for j:=1 to n do
if a[i,j]=1 then begin
for p:=1 to k do
if c[p]=j then gasit:=false;
if gasit then begin k:=k+1; c[k]:=j end
end;
i:=i+1
end;
if k=n then writeln('Toate nodurile sunt accesibile.')
else for i:=1 to k do write(c[i],',');
end.
Exerciţiu:Să se implementeze aplicaţia de mai sus în limbajul C.
88
Parcurgerea arborilor binari
♦ preordine:se vizitează rădăcina, se traversează subarborele stâng
în preordine, se traversează subarborele drept în preordine;
♦ inordine: se traversează subarborele stâng în inordine, se
vizitează rădăcina, se traversează subarborele drept în inordine;
♦ postordine: se traversează subarborele stâng în postordine, se
traversează subarborele drept în postordine, se traversează
rădăcina.
90
begin
creare(p);
preordine(p);
{Pentru procedura cautare}
read(x);
writeln(cautare(p,x));
{Pentru procedura nivel}
write('Nivelul= ');read(y);nivel(p,0,y);
{Pentru procedura drum_frunze}
drum_frunze(p,1);
{Pentru procedura adancime}
adancime(p,0,max);
writeln('Numarul de nivele este: ',max);
end.
Implementare în C++ :
#include <stdio.h>
#include <alloc.h>
#include <iostream.h>
#include <conio.h>
typedef struct nod{
int inf;
struct nod *st, *dr;
}arbore;
arbore *rad;
int a[10], max=0;
arbore *creare(){
int x;arbore *p;
cout<<"inf"; cin>>x;
if (x==0) return NULL;
else { (p)=(arbore*) malloc(sizeof(arbore)); (p)->inf=x;
cout<<"inf st. a lui"<<x; p->st=creare();
cout<<"inf dreapta a lui"<<x; p->dr=creare();
}
return p;
}
void preordine(arbore *p){
if (p){
printf("%d ",p->inf); preordine(p->st); preordine(p->dr);
}
}
91
void inordine(arbore *p){
if (p){
inordine(p->st); printf("%d",p->inf); inordine(p->dr);
}
}
void postordine(arbore *p){
if (p){
postordine(p->st); postordine(p->dr); printf("%d",p->inf);
}
}
int cautare(arbore *p, int x){
if(p){
if (p->inf==x) return 1;
return cautare(p->st,x)||cautare(p->dr,x);
}
else return 0;
}
void nivel(arbore*p, int k,int x){
if(p){
if (k==x) printf("%d ",p->inf);
nivel(p->st,k+1,x); nivel(p->dr,k+1,x);
}
}
void drum_frunze(arbore*p,int k){
int i;
if ((p->st)&&(p->dr)) {
a[k]=p->inf;
for (i=1;i<=k;i++) printf("%d ",a[i]);printf("\n");
}
else{
if(p) {
a[k]=p->inf;
drum_frunze(p->st,k+1); drum_frunze(p->dr,k+1);
}
}
}
void adancime(arbore *p, int k){
if (p) {
if (k>max) max=k; adancime(p->dr,k+1) ;adancime(p->st,k+1);
}}
92
void main(){
int x;
rad=creare();
preordine(rad);
printf("inf cautata:");scanf("%d", &x);
if (cautare(rad,x)) printf("exista");else printf("nu exista");
cout<<"nivelul";cin>>x;
cout<<"nodurile de pe nivelul "<<x<<":";nivel(rad,0,x);
cout<<"drumuri:";drum_frunze(rad,1);
adancime(rad,0);
printf("adancimea=%d",max);
}
Arbori binari de căutare
Arborele binar de căutare este un arbore binar în care pentru orice nod,
cheia din succesorul său stâng este mai mică decât cheia din nod, iar
cheia din succesorul său drept este mai mare decât cheia din nod. În
arborele binar de căutare informaţia din noduri este unică. Prin
parcurgerea în inordine a arborelui de căutare se obţine în ordine
crescătoare valorile din câmpurile cheie.
Crearea se realizează adăugând în arbore rând pe rând câte un
nod corespunzător fiecărei informaţii.
Adăugarea unu nod:
♦ dacă arborele nu are nici un nod se crează rădăcina;
♦ dacă arborele există se compară informaţia nodului nou cu cea din
nodul curent. Dacă este mai mare, se reia procesul pentru
subarborele din dreapta; dacă este mai mică, se reia pentru
subarborele din stânga, iar în caz de egalitate se afişează eroare.
Căutarea se realizează astfel: se caută în nodul curent; dacă
informaţia s-a găsit, algoritmul se încheie, astfel dacă informaţia este
mai mare decât informaţia din nodul curent, se caută în subarborele
drept al acestuia, altfel în subarborele stâng.
Aplicaţia 2.7.2. Program pentru crearea şi exploatarea unui arbore
binar de căutare.
Rezolvare:
Implementare Pascal:
type arbore=^nod;
nod = record inf:integer; st,dr:arbore end;
var p:arbore;x:integer;
93
procedure inserare(var p:arbore;x:integer);
var q:arbore;
begin
new(q);
q^.inf:=x;
q^.st:=nil;
q^.dr:=nil;
if p=nil then p:=q
else if p^.inf=x then write('Exista')
else if p^.inf<x then inserare(p^.dr,x)
else inserare(p^.st,x)
end;
procedure srd(p:arbore);
begin
if p<>nil then begin srd(p^.st); write(p^.inf,' '); srd(p^.dr) end
end;
procedure stergere(var p:arbore;x:integer);
var t:arbore;
begin
if p=nil then write('nu exista')
else if p^.inf<x then stergere(p^.dr,x)
else if p^.inf>x then stergere(p^.st,x)
else if p^.st=nil then begin
t:=p; p:=p^.dr; dispose(t)
end
else if p^.dr=nil then begin
t:=p;p:=p^.st;dispose(t);
end
else begin
t:=p^.st;
while t^.dr^.dr<>nil do t:=t^.dr;
p^.inf:=t^.dr^.inf; dispose(t^.dr);
t^.dr:=nil
end
end;
begin
read(x);
while x<>0 do begin inserare(p,x); read(x) end;
srd(p);read(x);stergere(p,x);srd(p);
end.
94
Implementare C++:
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
typedef struct nod {int inf; nod *st,*dr;}arbore;
arbore *rad;
arbore *q;
void adaug(arbore* &p,int x){
if (p==NULL){
p=new nod;
p->inf=x;
p->st=p->dr=NULL;
}
else if (p->inf>x) adaug(p->st,x);
else if (p->inf<x) adaug(p->dr,x);
else cout <<"informatia exista";
}
void creare(arbore* &p){
int x,n,i;
cout <<"n=";cin>>n;
for (i=1;i<=n;i++){
cout<<"inf";cin>>x;
adaug(p,x);
}
}
void inordine(arbore *p){
if (p){
inordine(p->st); printf("%d",p->inf); inordine(p->dr);
}
}
arbore *cauta(arbore*p, int x){
if (p==NULL) return NULL;
else if (p->inf<x) {
q=p;p=p->st;cauta(p,x);
}
else if (p->inf>x){
q=p;p=p->st; cauta(p,x);
}
else return p;
}
95
void sterge(arbore *&r,int x){
arbore *t,*q1,*p;
int a;
t=cauta(r,x);
if(t==NULL){
cout<<"informatia nu se gaseste";
getch();
}
else if (t->dr==t->st){
if (t->inf<q->inf) q->st=NULL;
delete t;
}
else if (t->st==NULL&&t->st){
if (q->inf<t->inf) q->dr=t->st; else q->st=t->st;
delete t;
}
else if (t->st==NULL&&t->dr){
if(q->inf>t->inf) q->st=t->dr; else q->dr=t->dr;
delete t;
}
else {
p=t;
while (p->st!=NULL){q=p;p=p->st;}
}
q1=t;
t->inf=p->inf;
if (p->dr==p->st){
q->st=NULL;
delete p;
}
else {
q->st=p->dr;
delete p;
}
while (q1->st&&q1->inf<q1->st->inf){
a=q1->inf;
q1->inf=q1->st->inf; q1->st->inf=a;
q1=q1->st;
}
}
96
void main(){
int x;
arbore *rad=0;
creare(rad);
inordine(rad);
sterge(rad,2);
}
Probleme propuse:
98
4. La un turneu participă n jucători, fiecare jucător jucând pe rând
împotriva celorlalţi jucători. Ştiind că nu există jocuri egale, să se
construiască o listă care să cuprindă toţi jucătorii astfel încat doi
jucători i, j sunt alături dacă jucătorul i la învins pe jucătorul j.
5. La curtea regelui Artur s-au adunat 2n cavaleri şi fiecare din ei are
printre cei prezenţi cel mult n-1 duşmani. Să se arate că Merlin,
consilierul lui Artur, poate să-i aşeze în aşa fel pe cavaleri la o
masa rotundă încât nici unul dintre ei să nu stea alături de vreun
duşman.
6. Fie G=(X,U) un graf conex cu n noduri. Să se determine eficient
cel mai mic k astfel încât ştergând nodurile etichetate cu 1,2...k, în
această ordine să rezulte un graf ale cărui componente conexe au
toate cel mult n/2 noduri.
7. Să se determine, într-un graf conex, un ciclu care conţine două
noduri date, dar nu conţine un al treilea nod.
8. Numim transpusul unui graf G = (X,U), graful care are aceeaşi
mulţime de noduri, arcele sale fiind arcele grafului G, dar având
sens opus. Dându-se G prin matricea de adiacenţă sau prin liste de
vecini, să se determine în fiecare caz transpusul grafului dat.
9. Find date n persoane în care fiecare persoană se cunoaşte pe sine
şi eventual alte persoane. Să se formeze grupuri în care fiecare
persoană să cunoască toate celelalte persoane din grup (o persoană
aparţine unui singur grup). Relaţia “x cunoaşte pe y” nu este în
mod normal nici simetrică, nici tranzitivă.
Indicaţie: Se asociază problemei date un graf orientat cu n noduri şi se
construieşte matricea de adiacenţă (a[i,j]=1 daca i cunoaste pe j =i 0
dacă i nu cunoaşte pe j). Pentru fiecare persoană neataşată la un
moment dat unui grup se va construi grupul din care face parte
aceasta. Soluţia nu este unică.
10. Să se determine, într-un graf turneu, un drum elementar care trece
prin toate vârfurile. Un graf turneu este un graf orientat cu
proprietatea că între oricare două vârfuri distincte există un arc şi
numai unul.
Indicaţie: Se adaugă arcul format din nodurile 1 şi 2 într-o listă liniară.
Fiecare din vârfurile următoare se adaugă la drumul creat anterior fie
în faţă, fie la sfârşit, fie intercalat în listă.
11. Fie G=(X,U) un graf ponderat. Să se calculeze diametrul grafului.
Se numeşte diametrul unui graf, notat d(G), d(G)=max{l[i]/ i∈X},
unde l[i] este lungimea drumului maxim care are ca extremitate
iniţială vârful i.
99
12. Fie G un graf orientat în care fiecare arc are asociat un cost pozi-
tiv. Să se determine un circuit elementar care să treacă prin toate
vârfurile grafului care să aibă cost minim.
13. Se consideră un grup de n persoane. Fiecare persoana are cel puţin
n/2 prieteni şi cel mult k duşmani în grup. Una din persoane are o
carte pe care fiecare doreşte să o citească. Să se determine o mo-
dalitate prin care cartea să circule pe la fiecare persoană o singură
dată, transmiterea ei facându-se numai între doi prieteni, iar în
final cartea să ajungă din nou la proprietarul cărţii.
14. Pentru un graf dat în numerotare aciclică (orice arc u = (x,y) din U
satisface condiţia x<y), determinaţi distanţa minimă de la vârful 1 la
toate celelate vârfuri z pentru care există drumuri de la 1 la z, precum şi
câte un drum de lungime minimă. Sunt date arcele şi lungimile lor.
15. Pătratul unui graf orientat G se determină astfel: există arc de la x
la y în pătratul unui graf dacă există în G un drum de lungime 2 de
la x la y. Să se determine pătratul unui graf când graful este repre-
zentat fie prin liste de adiacenţă, fie prin matricea de adiacenţă.
16. Se dă un graf orientat aciclic şi se cere aranjarea vârfurilor sale
astfel încât orice arc are prima extremitate înaintea celei de-a doua
extremităţi în aranjare.
17. Se dă un graf orientat aciclic, în care numărul maxim de arce în
orice drum este k. Să se determine o partiţie a mulţimii vârfurilor
grafului în cel mult k submulţimi, astfel încât pentru orice două
noduri x,y din aceeaşi submulţime să nu existe drum de la x la y şi
nici de la y la x.
Indicaţie: Graful este aciclic, deci există noduri cu gradul 0 şi se
formează prima submulţime cu aceste noduri şi apoi se vor elimina
aceste noduri din graf împreuna cu arcele ce pleacă din ele obţinându-
se un graf orientat aciclic pentru care se reia procedeul.
18. Un graf orientat se numeşte semi-conex dacă pentru pentru orice
pereche de vârfuri diferite x şi y există drum de la x la y sau drum
de la y la x. Să se verifice dacă G este semi-conex.
19. Să se realizeze un program care să deseneze un graf (planar)şi apoi să
se marcheze succesiv pe desen drumul de lungime minimă între două
noduri date.
20. Se consideră o clasă de n ( n <= 40 ) cursanţi între care există relaţii de
simpatie, nu neaparat reciproce. Să se formeze grupuri de cursanţi între
care există relaţii de prietenie reciprocă. Un cursant nu poate să
aparţină mai multor grupuri.
100
3. Metode pentru rezolvarea problemelor
3.1. Metoda Divide et Impera
3.1.1. Prezentarea metodei
Metoda generală de programare cunoscută sub numele de divide et
impera (“dezbină şi stapâneşte”) constă în împărţirea repetată a unei
probleme în subprobleme de acelaşi tip, dar de dimensiune mai mică,
urmată de combinarea soluţiilor subproblemelor rezolvate pentru a
obţine soluţia problemei iniţiale. Fiecare subproblemă se rezolvă
direct dacă dimensiunea ei este suficient de mică încât să poată fi
rezolvată imediat cu un procedeu specific, altfel este împărţită în
subprobleme mai mici folosind acelaşi procedeu prin care a fost
descompusă problema iniţială. Procedeul se reia până când, în urma
descompunerilor repetate, se ajunge la probleme care admit rezolvare
imediată.
Algoritmul fiind de natură repetitivă şi deoarece subproblemele
au aceeaşi formă cu cea a problemei iniţiale, metoda “Divide et
impera” poate fi implementată elegant folosind o funcţie recursivă.
În continuare este dată funcţia generală care implementează
algoritmul.
101
Rezolvare:
program divizor_comun;
var x:array[1..25] of integer; n, i:integer;
function Divizor(a,b:integer):integer;
begin
while a<>b do if a>b then a:=a-b else b:=b-a;
Divizor := a
end;
function cmmdc(lo,hi:integer):integer;
var m:integer;
begin
if (hi-lo<=1) then cmmdc := Divizor(x[lo],x[hi])
else begin
m:=(lo+hi) div 2;
cmmdc:= Divizor(cmmdc(lo,m), cmmdc(m+1,hi));
end;
end;
begin
write('n = '); readln(n); writeln('Introduceti numerele');
for i:=1 to n do begin write('x[',i,'] = '); readln(x[i]) end;
writeln('cmmdc:= ', cmmdc(1,n));
end.
R3.1.2. [Căutare binară] Fie x1, x2,…,xn un şir de numere întregi
ordonate crescător şi x un număr întreg. Să se verifice dacă x se află
printre elementele şirului şi dacă da, să se afişeze poziţia acestuia.
Rezolvare:
program cautare;
uses crt;
var x:array[1..100] of integer; nr:integer;
function cauta(lo,hi:integer):integer;
var m:integer;
begin
if (lo<=hi) then begin m:=(lo+hi) div 2;
if nr=x[m] then cauta:=m
else if nr<x[m] then cauta:=cauta(lo,m-1)
else cauta:=cauta(m+1,hi)
end
else cauta:=0
end;
102
var n,i,pos:integer;
ch:char;
begin
write('n = ');readln(n);
writeln('Introduceti numerele');
for i:=1 to n do begin write('x[',i,'] = '); readln(x[i]) end;
repeat
writeln;
write('Numarul cautat = ');
readln(nr);
pos := cauta(1,n);
if pos <> 0 then
writeln(nr,' se afla in sir la pozitia ', pos)
else writeln(nr,' nu se afla in sir!');
write('Continuati (y/n) ?[y] ');
ch:=UpCase(readkey);
until ch = 'N';
end.
R3.1.3. [Sortare rapidă] Fie n ∈ N* şi numerele x1, x2,…,xn. Să se scrie
o procedură recursivă de sortare (quicksort) în ordine crescătoare a
numerelor date.
Rezolvare:
#include <stdio.h>
void QSort (int *table, int left,int right){
int leftp,rightp,aux;
unsigned type = 1;
leftp =left;
rightp=right;
do{
if ( table[leftp]>table[rightp] ){
type ^= 1;
aux = table[leftp];
table[leftp] = table[rightp];
table[rightp] = aux;
}
else type ? rightp--: leftp++;
}while (leftp < rightp);
if ( leftp-left > 1) QSort(table,left,leftp-1);
if ( right-rightp >1) QSort(table,rightp+1,right);
}
103
void main(){
int n,i;
int x[100];
printf(“n = ”); scanf(“%d”,&d);
for (i=0;i<n;i++) scanf(“%d”,&x[i]);
Qsort(x,0,n-1);
for (i=0;i<n;i++) printf(“%8d”,x[i]);
}
R3.1.4. [Problema turnurilor din Hanoi] Se dau 3 tije numerotate cu 1,
2, 3 şi n discuri perforate, cu diametre diferite. Iniţial toate discurile
se află pe tija 1 în ordinea descrescatoare a diametrelor lor, în sensul
de la bază la vârful tijei. Se pune problema de a muta toate cele n
discuri pe tija 2 (utilizând şi tija 3) şi respectând urmatoarele reguli:
• a fiecare pas se mută un singur disc;
• pe fiecare tijă deasupra unui disc pot apare numai discuri
cu diametru mai mic.
Rezolvare:
#include<stdio.h>
void Hanoi(int n, int a, int b){
if (n==1) printf("\%d - %d\n",a,b);
else {
Hanoi(n-1, a, 6-a-b);
printf("\%d - %d\n",a,b);
Hanoi(n-1, 6-a-b,b);
}
}
void main(){
int n;
printf("Numarul de discuri = "); scanf("%d",&n);
Hanoi(n,1,2);
}
R3.1.5. [Sortare prin interclasare] Se consideră un vector ne numere
intregi de lungime n. Descrieţi un algoritm de ordonare a numerelor
prin metoda de sortare prin interclasare.
Rezolvare:
#include <stdio.h>
#define MAX 100
104
void MSort(int tabel[],int temp[], int lo, int hi){
int mid, k, t_lo, t_hi;
if (lo >= hi) return;
mid = (lo+hi) / 2;
MSort(tabel,temp, lo, mid);
MSort(tabel,temp, mid+1, hi);
t_lo = lo;
t_hi = mid+1;
for (k = lo; k <= hi; k++)
if ( (t_hi > hi || tabel[t_lo] < tabel[t_hi]) && (t_lo <= mid) )
temp[k] = tabel[t_lo++];
else temp[k] = tabel[t_hi++];
for (k = lo; k <= hi; k++)
tabel[k] = temp[k];
}
void main(){
int n, i;
int tabel[MAX];
int temp[MAX];
printf("n = ");
scanf("%d",&n);
printf("Introduceti numerele:\n");
for(i=0;i<n;i++){
printf("tabel[%d] = ",i);
scanf("%d",&tabel[i]);
}
MSort(tabel, temp, 0, n-1);
for(i=0;i<n;i++) printf("%d ",tabel[i]);
}
3.1.3. Probleme propuse
1. Fie x1, x2,…,xn un şir de numere reale. Să se determine max{x1,
x2,…,xn}.
2. Se dă x1, x2,…,xn (cu n∈N) un şir de numere, descrieţi un program
“Divide et Impera” care să determine al k-lea cel mai mic element
din şir (k ∈N, k<n).
3. Se consideră un vector de x cu n componente numere intregi. Să
se sorteze componentele vectorului folosind metoda de sortare
prin interclasare.
105
4. Se dă o placă de tablă cu lungimea x şi lăţimea y având n găuri
date prin coordonatele lor întregi. Se cere să se decupeze o bucată
dreptunghiulară de arie maximă şi fără găuri ştiind că sunt permise
numai tăieturi orizontale şi verticale.
5. Se consideră un vector de lungime n. Se numeşte plierea
vectorului operaţia de suprapunere a unei jumătăţi (donatoare)
peste cealaltă jumătate (receptoare). Dacă n este impar elementul
din mijloc se elimină. Elementele rezultate după pliere vor avea
numeroatarea jumătăţii receptoare. Plierea se poate repeta până
când se obţine un singur element (final). Scrieţi un program care
să determine toate elementele finale posibile şi să afişeze
succesiunile de plieri corespunzătoare. Rezolvaţi aceiaşi problemă
ţinând cont că la pliere fiecare element receptor se dublează şi din
acesta se scade elementul donator corespunzător.
6. Rezolvaţi problema turnurilor din Hanoi folosint două tije de
manevră. Comparaţi numărul de mutări efectuate.
7. Fie P(x) un polinom de grag n cu coficienţi reali. Să se evalueze
polinomul în punctul x0 folosind metoda “Divide et Imera”.
8. Scrieţi o procedură “Divide et Impera” pentru inversarea unui şir
de caractere.
9. Se dă un dreptunghi prin dimensiunile sale numere naturale.
Dreptunghiul trebuie descompus în pătrate cu laturi numere
naturale, paralele cu laturile dreptunghiului iniţial. Se cere
numărul minim de pătrate în care se poate descompune
dreptunghiul.
10. Se dau un pătrat şi un cerc. Se cere să se calculeze aria lor comună
cu precizie de o zecimală. Coordonatele se citesc de la tastatură şi
sunt numere reale. Aria se va afişa pe ecran.
11. Un arbore cartezian al unui vector este un arbore binar definit
recursiv astfel: rădăcina arborelui este elementul cel mai mic din
vector; subarborele stâng este arborele cartezian al subvectorului
stâng (faţă de poziţia elementului din rădăcină); subarborele drept
este arborele cartezian al subvectorului drept. Se dă un vector de
dimensiune n. Să se afişeze arborele său cartezian.
106
3.2. Metoda programării dinamice
3.2.1. Principii fundamentale ale programării dinamice
Programarea dinamică, ca şi metoda divide et impera, rezolvă
problemele "combinând" soluţiile subproblemelor. Un algoritm bazat
pe programare dinamică rezolvă fiecare subproblemă o singură dată şi,
apoi, memorează soluţia într-un tablou, prin aceasta evitând
recalcularea soluţiei dacă subproblema mai apare din nou şi
subprobemele care apar în descompunere nu sunt independente.
Metoda programării dinamice se aplică problemelor de
optimizare. În problemele de optim metoda constă în determinarea
soluţiei pe baza unui şir de decizii d1, d2, d3....dn, unde di transformă
problema din starea si-1 în starea si.
Paşii pentru rezolvarea unei probleme folosind programarea
dinamică:
1. Caracterizarea structurii unei soluţii optime;
2. Definirea recursivă a valorii unei soluţii optime;
3. Calculul valorii unei soluţii optime
4. Construirea unei soluţii optime din informaţia calculată.
Principii fundamentale ale programării dinamice:
1. Dacă d1, d2, ... dn este un şir optim de decizii care duc un
sistem din starea iniţială în starea finală, atunci pentru orice i
(1≤i≤n) d1, d2, ... di este un şir optim de decizii.
2. Dacă d1, d2, ... dn este un şir optim de decizii care duc un
sistem din starea iniţială în starea finală, atunci pentru orice i
(1≤i≤n) di, di+1, ... dn este un şir optim de decizii.
3. Dacă d1, d2, ... , di, di+1 ... dn este un şir optim de decizii care
duc un sistem din starea iniţială în starea finală, atunci pentru
orice i (1≤i≤n) d1, d2,... , di şi di, di+1, ... dn sunt două şiruri
optime de decizii.
111
a[n,n]=1;
a[n,k]=a[n-k,0] pentru n≤2k;
a[n,k]=Σa[n-k,i] pentru i de la 1 la k.
Implementare C:
#include <stdio.h>
void main(){
int n,i,k,j,p,a[100][100];
printf("n=");scanf("%d",&n);
a[1][0]=1;a[1][1]=1;
for( i=2;i<=n;i++){
a[i][0]=0;
for(k=1;k<=i;k++){
if(k==i) a[i][k]=1;
else if(i<2*k) a[i][k]=a[i-k][0];
else {
a[i][k]=a[i-k][k];
for(int l=1;l<=k-1;l++)
a[i][k]=a[i][k]+a[i-k][l];
}
a[i][0]=a[i][0]+a[i][k];
}
}
printf("nr de moduri=%d",a[n][0]);
}
Exerciţiu: Să se implementeze în Pascal aplicaţia de mai sus.
R3.2.5. [Drum] Dându-se un tablou bidimensional cu elemente
numere naturale. Să se determine un traseu de la poziţia 1,1 la poziţia
n,m, deplasarea făcându-se numai în direcţiile S şi E, astfel încât
suma elementelor de pe traseu să fie maximă.
Rezolvare: Implementarea Pascal este:
var i,j,n,m,max,p,q:integer;
a,l:array[1..10,1..10]of integer;
begin
read(m,n);
for i:=1 to n do for j:=1 to m do read(a[i,j]);
l[1,1]:=a[1,1];
for i:=2 to m do l[1,i]:=l[1,i-1]+a[1,i];
for i:=2 to n do l[i,1]:=l[i-1,1]+a[i,1];
for i:=2 to n do for j:=2 to m do
112
if l[i-1,j]>l[i,j-1] then l[i,j]:=l[i-1,j]+a[i,j]
else l[i,j]:=l[i,j-1]+a[i,j];
writeln(l[n,m]); max:=l[n,m];p:=n;q:=m; write(a[n,m],' ');
while (p<>1) and (q<>1) do begin
if l[p-1,q] = l[p,q]-a[p,q] then p:=p-1 else q:=q-1;
write(a[p,q],' ');
end;
write(a[1,1]);
end.
Exerciţiu: Să se implementeze aplicaţia de mai sus în C.
3.2.3. Probleme propuse
1. [Triunghi] Se consideră un triunghi de numere. Să se calculeze cea
mai mare dintre sumele numerelor ce apar pe drumurile ce pleacă din
vârf şi ajung la bază şi să se reconstituie drumul de sumă maximă. În
punctul (i,j) se poate ajunge numai din (i-1,j) sau (i-1,j-1).
Exemplu:
N=3
6
3 8
8 4 1
suma maximă este 18 şi drumul 6 8 4
Indicaţie: Se construieşte tabloul c astfel c[i,j]=max{a[i,j]+ c[i+1,j],
a[i,j]+ c[i+1,j+1]} (varianta mersului “înainte”). c[1,1] este suma
maximă cerută.
2. [Înmulţirea optimă a unui şir de matrice] Se dau n matrice.
Asociativitatea înmulţirii a două matrice ne oferă mai multe
posibilităţi de a calcula produsul şi care au un număr diferit de
operaţii. Să se determine o posibilitate de asociere a înmulţirii
matricelor astfel încât numărul de operaţii să fie minim.
Indicaţie: Se construieşte tabloul bidimensional L, unde l[i,j] repre-
zintă numărul minim de înmulţiri pentru a efectua produsul AiAi+1.....Aj.
3. [Triangularizarea optimă a poligoanelor] Se dă un poligon convex şi
o funcţie de pondere p definită pe triunghiurile formate de laturile şi
diagonalele poligonului. Să se găsească o triangulare care minimizea-
ză suma ponderilor triunghiurilor din triangularizare.
Indicaţie Există o corespondenţă între triangularizarea unui poligon şi
parantezarea unei expresii cum ar fi produsul unui şir de matrici.
4.[ Tipărirea uniformă] Textul de intrare este o succesiune de n cuvin-
te de lungimi l1, l2,...ln, lungimea fiind măsurată în caractere. Se doreş-
113
te tipărirea uniformă a paragrafului pe un anumit număr de linii, fieca-
re linie având cel mult m caractere astfel: dacă o linie conţine cuvinte-
le de la cuvântul i la cuvântul j, cu i ≤j iar între cuvinte se lasă exact
un spaţiu. Să se minimizeze suma cuburilor numărului de spaţii supli-
mentare de la sfârşitul liniilor, în raport cu toate liniile, mai puţin ultima.
5. [Problema patronului] Un patron a cumpărat un calculator şi doreşte
să înveţe să lucreze cu el. Pentru aceasta va umple un raft de cărţi din
colecţia “Informatica în lecţii de 9 minute şi 60 secunde”. Raftul are
lungimea L cm (L număr natural). Seria dispune de n titluri 1, 2, …,n
având grosimile g1, g2, ..., gn cm (numere naturale). Să se selecteze
titlurile pe care le poate cumpăra patronul, astfel încât raftul să fie
umplut complet (suma grosimilor cărţilor cumpărate să fie egală cu
lungimea raftului) şi numărul cărţilor achiziţionate să fie maxim.
Olimpiada Naţională de Informatică 1996
Indicaţie: Se construieşte tabloul bidimensional a unde a[i,j] reprezin-
tă numărul maxim de cărţi dintre primele i (în ordinea dată la intrare)
cu lungimea totală j sau, 0 dacă nu există nici o submulţime a mulţimii
primelor i cărţi cu lungimea totală j.
6. [Planificarea unei recepţii] Corporaţia AMC are o structură ierarhi-
că, relaţiile de subordonare formează un arbore în care rădăcina este
preşedintele. Fiecare angajat are un coeficient de convieţuire (număr
real). Preşedintele doreşte să organizeze o petrecere astfel încât nici un
angajat să nu se întâlnească cu seful său direct. Informaticianul Tom
trebuie să alcătuiască lista invitaţilor astfel încât suma coeficienţilor de
convieţuire a invitaţilor să se maximizeze şi preşedintele să participe
la propia petrecere.
7. [Mouse] Un experiment urmăreşte comportarea unui şoricel pus
într-o cutie dreptunghiulară, împărţită în mxn cămăruţe egale de formă
pătrată. Fiecare cămăruţă conţine o anumită cantitate de hrană. Şorice-
lul trebuie să pornească din colţul (1,1) al cutiei şi să ajungă în colţul
opus, mâncând cât mai multă hrană. El poate trece dintr-o cameră în
una alăturată (două camere sunt alăturate dacă au un perete comun),
mănâncă toată hrana din cămăruţă atunci când intră şi nu intră
niciodată într-o cameră fără hrană. Stabiliţi care este cantitatea maxi-
mă de hrană pe care o poate mânca şi traseul pe care îl poate urma
pentru a culege această cantitate maximă. Se dă n, m şi cantitatea de
hrană existentă în fiecare cămeruţă (numere între 1 şi 100).
Olimpiada judeţeană de informatică, 2002
114
Exemplu:
24
1263
3412
Ieşire:
7 21
1 1 --> 2 1 --> 2 2 --> 1 2 --> 1 3 --> 1 4 -->2 4
8. [Semne] Pentru n număr natural, să se găsească o combinaţie de semne
+ şi - (adică un vector x = (x(1), x(2), ..., x(k)), x(i) se află în <-1, 1>) şi
un număr k natural nenul astfel încât:
n = x(1)*12+x(2)*22+...+x(k)*k2.
Datele se citesc dintr-un fişier text ce conţine pe fiecare linie câte un
număr ce reprezintă valorile lui n pentru care se doresc reprezentări ca
mai sus. Datele de ieşire vor fi introduse într-un fişier text pe câte o
linie combinaţia de semne corespunzătoare.
Exemplu:
Intrare:
2
4
8
5
Ieşire:
---+
--+
--++--+
++--+
Indicaţie: Pentru k începând de la 1, se găsesc într-o listă numerele care
se pot obţine cu k semne; lista pentru k se obţine din cea pentru k-1.
Pentru unele numere k este foarte mare şi programul nu ar intra în
timp. O altă soluţie ar fi folosirea observaţiei:
(n+3)2-(n+2)2-(n+1)2+n2=(n+3+n+2)*1-(n+1+n)*1=2n+5-2n-1=4
Prin adăugarea secvenţei + - - + se ajunge de la un numar n la n+4.
Dacă am obţine secvenţele pentru n = 0, 1, 2 şi 3, am rezolva
problema. Acestea sunt:
0 secvenţa vidă
1+
2 - - - + (dată în exemplu)
3 - (pentru -1), apoi + - - +
115
9. [Şah] a) Dându-se două poziţii pe o tablă de şah de dimensiune
pătratică nxn, să se determine cel mai scurt drum dintre acestea
utilizând mutările calului.
b) Determinaţi numărul minim de cai care pot fi amplasaţi pe o tablă
de şah de dimensiune nxm astfel încât să nu se atace.
10. [Linii navale] Pe malul de nord şi cel de sud al unui fluviu există n
oraşe. Fiecare oraş are un unic oraş prieten pe celălalt mal; nu există
două oraşe pe un mal având acelaşi priten pe celălalt mal. Intenţia este
ca oraşele prietene să se lege printr-o linie navală. Se impune însă
restricţia ca să nu existe linii navale care să se intersecteze. Să se
determine numărul maxim de linii navale care pot fi înfiinţate, cu
respectarea condiţiei de mai sus. Pe prima linie a fişierului de intrare
apare numărul n de perechi de oraşe prietene, iar pe următoarele n linii
apar perechile de oraşe prietene (primul pe malul de nord, iar al doilea
pe malul de sud), fiecare oraş fiind specificat prin distanţa sa (cel mult
egală cu 6000) faţă de kilometrul 0 al fluviului.
Indicaţie: Se ordonează posibilele linii navale după primul argument
şi se determină cel mai lung subşir crescător format din coordonatele
celui de-al doilea argument. (vezi problema rezolvată 1).
11. [Drumuri minime] Se consideră un graf orientat, fiecare arc având
un cost ataşat. Se cere să se determine pentru fiecare pereche de
vârfuri ( i, j) şi să se tipărească lungimea drumului minim de la i la j.
12. [Submulţimi de sumă dată] Să se determine pentru un vector dat
dacă un număr k se poate scrie ca sumă de numere din vector, un
element din vector se poate folosi o dată.
Indicaţie: Se construieşte un tablou a cu valori logice, unde a[i] este
true dacă i se poate scrie ca sumă de elemente din vectorul dat şi false
în caz contrar.
116
În general, datele de intrare pentru un algoritm Greedy se prezintă sub
forma unei mulţimi finite, iar soluţia este o submulţime sau o
permutare a datelor de intrare în aşa fel încât să fie îndeplinite anumite
condiţii de optim. Condiţiile de optim cer determinarea unei soluţii
care maximizează sau minimizează o funcţie dată, numită funcţie
obiectiv.
Dacă un element este inclus în soluţie el va rămâne în această
mulţime, nu se face nici o revenire asupra unei decizii luate.
Selectarea unui element la un moment dat poate depinde de
elementele alese până la acel moment dar nu depinde de cele care
urmează să fie alese ulterior.
Dacă un element a fost selectat, dar nu poate face parte din
soluţie atunci acest element nu va mai fi luat în calcul la alegerile
următoare. În acest fel se poate ajunge rapid la o soluţie, dar nu se
asigură (pentru toate problemele) optimalitatea globală. Există şi
probleme pentru care o astfel de metodă nu conduce la soluţie, deşi
aceasta există. Problemele care se pot rezolva folosind algoritmi de tip
Greedy trebuie să verifice două proprietăţi: proprietatea alegerii
Greedy şi substructura optimală.
Proprietatea alegerii Greedy spune că se poate ajunge la o
soluţie de optim global dacă la fiecare pas de decizie se selectează un
element care îndeplineşte criteriul de optim local. Proprietatea de
structură optimală spune că soluţia optimală a problemei conţine
soluţiile optimale ale subproblemelor.
O problemă care se va rezolva folosind o strategie Greedy este
dată de:
• O mulţime finită de “candidaţi” care reprezintă datele de
intrare;
• O funcţie care verifică dacă o anumită mulţime de elemente
constituie o soluţie posibilă, nu neaparat optimă, a
problemei;
• O funcţie care verifică dacă o submulţime a datelor de
intrare este o soluţie parţială a problemei;
• O funcţie de selecţie care alege la orice moment cel mai
potrivit candidat dintre elementele nefolosite încă;
• O funcţie obiectiv care trebuie minimizată sau maximizată.
117
function greedy(C) {C este mulţimea datelor de intrare }
S←∅ {S este multimea care va conţine soluţia}
while not Soluţie(S) and C ≠ ∅ do
begin
x ← select(C)
C ← C \ {x}
if Posibil(S ∪ {x}) then S ← S ∪ {x}
end
if Solutie(S) then return S
else return write(‘nu exista soluţie’)
Această metodă îşi găseşte multe aplicaţii în teoria grafurilor la
determinarea unui arbore parţial de cost minim (Kruskal, Prim), la
determinarea drumurilor de cost minim de la un vârf la celelalte
vârfuri ale unui graf (Dijkstra), compresia datelor (arbori Huffman)
ş.a.
3.3.2. Probleme rezolvate
R3.3.1. [Problema continuă a rucsacului] Avem la dispoziţie un
rucsac cu care se poate transporta o greutate maximă G. Trebuie să
alegem din n obiecte pentru care se cunoaşte greutatea gi şi profitul pi
care se obţine prin transportul obiectului i cu rucsacul. Să se
determine obiectele care trebuiesc alese pentru transport astfel încât
profitul obţinut să fie maxim, iar greutatea totală a acestora să nu
depăşească G ştiind că putem lua orice parte dintr-un obiect.
Rezolvare: Programul în C este:
#include <stdio.h>
#define MAX 25
void main(){
int p[MAX]; int g[MAX];
int n,i,j,aux,nr[MAX];
float G, gr,profit,sol[MAX];
printf("Greutatea maxima G = ");scanf("%f",&G);
printf("Numarul de obiecte: ");
scanf("%d", &n);
for (i=0; i<n; i++){
printf("Obiectul nr. %d:\n",i+1);
printf("Greutatea = "); scanf("%d",&g[i]);
printf("Profitul = "); scanf("%d",&p[i]);
sol[i] = 0.0; nr[i] = i;
}
118
/*
ordonare descrescatoare dupa raportul p/g
*/
for (i=0;i<n-1;i++) for (j=i+1;j<n;j++)
if(p[i]/g[i] < p[j]/g[j]){
aux=p[i]; p[i]=p[j]; p[j]=aux;
aux=g[i]; g[i]=g[j]; g[j]=aux;
aux=nr[i]; nr[i]=nr[j]; nr[j]=aux;
}
/*alegere */
gr = G;
for (i=0; i<n && g[i]<gr; i++){
sol[i] = 1.0; //100%
gr -= g[i];
}
if (i < n) sol[i] = gr/g[i];
/*afisare zezultate */
profit = 0.0;
for (i=0;i<n;i++)
if(sol[i] > 0){
printf("Obiect %d - %5.2f%%\n", nr[i]+1, sol[i] *100);
profit += sol[i] * p[i];
}
printf("Profit = %5.2f", profit);
}
R3.3.2.[Planificarea activităţilor] Într-o sală, într-o zi trebuie plani-
ficate n activităţi, pentru fiecare activitate se cunoaşte intervalul în
care se desfăşoară [s, f). Se cere să se planifice un număr maxim de
activităţi astfel încât să nu se suprapună.
Rezolvare:Programul Pascal este:
program Activitati;
uses crt;
const max=100;
var n,i,j,aux:integer;
s,f:array[1..max] of integer;
sol:array[1..max] of 0..1;
nsol, finish:integer;
begin
{ citire date }
119
write('Nr de activitati = '); readln(n);
for i:=1 to n do
begin
writeln('Activitatea nr. ',i,':');
write('Start = '); readln(s[i]);
write('Finish = '); readln(f[i]);
sol[i]:=0;
end;
{ordonare după termenul final}
for i := 1 to n-1 do
for j := i + 1 to n do
if ( f[i] > f[j]) then
begin
aux:=s[i]; s[i]:=s[j]; s[j]:=aux;
aux:=f[i]; f[i]:=f[j]; f[j]:=aux;
end;
{calcul}
finish := 0;
for i := 1 to n do
if (s[i] >= finish ) then
begin
sol[i]:=1;
finish := f[i];
end;
{afisare rezultate}
writeln('Solutie:'); j := 1;
for i := 1 to n do
if sol[i]=1 then
begin
writeln('Activitatea nr. ',j,': ',
s[i], ' - ' ,f[i]);
j := j + 1;
end;
end.
R3.3.3. [Schimbarea banilor] Presupunem că a avem la dispoziţie k
tipuri de monede cu valorile c0, c1,… ck-1 unde c∈N*, să se scrie un
program care să determine o modalitate de schimb a unei sume S
folosind un număr minim de monede (numărul de monede din fiecare
tip fiind nelimitat).
Rezolvare: Programul C este:
120
#include<stdio.h>
#include<conio.h>
void main(){
int i,j,k,c,S; int sol[100]; int x,xmax;
/*citire date */
printf("k = "); scanf("%d",&k); printf("c = "); scanf("%d",&c);
printf("S = "); scanf("%d",&S);
/*calcul */
xmax=1; for(i=1; i<k; i++) xmax*=c;
x = xmax;
for(i=0; S>0; i++){ sol[i] = S / x; S %= x; x /= c; }
/*afisare */
x = xmax;
for(j=0; j<i; j++,x/=c)
if(sol[j]>0) printf("%d monede cu valoarea %d\n", sol[j], x);
getch();
}
R3.3.4. [Numere frumoase] Numerele frumoase sunt acele numere
care au în descompunerea lor numai factori primi de 2, 3 şi 5. Fiind
dat un număr natural n<1000, să se afişeze pe ecran primele n
numere frumoase.
Rezolvare: Programul Pascal este:
program nrFrumoase;
const max = 1000;
function min(a,b:integer):integer;
begin if a <= b then min:=a else min:=b end;
var
t,n2,n3,n5:integer;
f:array[1..max] of longint;
i,j,k,l,n:integer;
begin
write('n = '); readln(n);
n2:=2; i:=1; n3:=3; j:=1; n5:=5; k:=1; t:=1; l:=1; f[1]:=1;
while(l<=n) do
begin
t:=min(n2,min(n3,n5));
l:=l+1; f[l]:=t;
if t = n2 then begin inc(i); n2 := 2*f[i] end;
if t = n3 then begin inc(j); n3 := 3*f[j] end;
121
if t = n5 then begin inc(k); n5 := 5*f[k] end
end;
for i:=1 to n do write(f[i],' ');
readln;
end.
R3.3.5. [Copaci şi ciori] Pe n copaci aşezaţi în cerc se află n-1 ciori,
maxim una pe fiecare copac. Dându-se o configuraţie iniţială şi una
finală a ciorilor şi ştiind că la un moment dat o singură cioară poate
zbura de pe copacul ei pe cel liber, să se scrie un program care să de-
termine o secvenţă de zboruri pentru a ajunge la configuraţia finală.
Rezolvare: Programul C este:
#include <stdio.h>
#define MAX 10
int initial[MAX]; int final[MAX]; int n;
int CopacLiber(){
int i=0; while(initial[i]!=0) i++; return i; }
int Copac(int c){
int i=0; while(initial[i] != c) i++; return i; }
void Zboara(int s,int d){
printf("Cioara %d zboara de pe copacul %d pe %d !\n", \
initial[s], s+1,d+1);
initial[d] = initial[s]; initial[s] = 0;
}
void main(){ int i, k;
printf("n = "); scanf("%d",&n);
printf("Introduceti configuratia initiala (0 pt. liber):\n");
for(i=0;i<n;i++)
{printf("initial[%d] = ",i+1); scanf("%d",&initial[i]);}
printf("Introduceti configuratia finala (0 pt. liber):\n");
for(i=0;i<n;i++)
{printf("final[%d] = ",i+1);scanf("%d",&final[i]);}
for(i=0;i<n;i++)
if (final[i] && initial[i] != final[i]){
if(initial[i]) {
k = CopacLiber(); Zboara(i,k);
}
k = Copac(final[i]); Zboara(k,i);
}
}
122
R3.3.6. [Problema comis-voiajorului] Un comis-voiajor trebuie să
viziteze un număr de n oraşe şi să revină în oraşul de plecare.
Cunoscând legăturile dintre oricare două oraşe se cere să se afişeze
cel mai scurt traseu posibil pe care poate să-l parcurgă comis-
voiajorul ştiind că nu trebuie să treacă de două ori prin acelaşi oraş.
Rezolvare: Programul Pascal este:
program comis;
const max = 25;
var harta:array[1..max,1..max] of integer;
traseu:array[1..max] of integer;
v:array[1..max] of 0..1;
i,j,k,min,n,lungime,pos:integer;
begin
write('n = '); readln(n);
for i:=1 to n-1 do for j:=i+1 to n do
begin
write('distanta[',i,', ', j,'] = '); readln(harta[i,j]);
harta[j,i]:=harta[i,j];
end;
write('Orasul de pornire = '); readln(k);
lungime:=0; traseu[1]:=k; v[k]:=1;
for i:=2 to n do
begin
min:=maxint;
for j:=1 to n do
if v[j] = 0 then
if harta[k, j] < min then
begin
min := harta[k, j];
pos := j
end;
inc(lungime,min); traseu[i]:=pos; v[pos]:=1; k:=pos
end;
inc(lungime,harta[k,1]);
for i:=1 to n do write(traseu[i]:3);
writeln(traseu[1]:3);
writeln('lungimea = ', lungime);
readln;
end.
123
3.3.3. Probleme propuse
1. [Problema planificării optime a lucrărilor] Se presupune că avem de
executat un număr de n lucrări, cunoscându-se pentru fiecare lucrare i
termenul de finalizare ti şi penalizarea pi plătită în cazul în care
lucrarea nu este predată la termen. Ştiind că fiecare lucrare este
executată într-o unitate de timp şi că nu se pot executa mai multe
lucrări simultan, să se planifice ordinea de execuţie a lucrărilor astfel
încât penalizarea totală să fie minimă.
2. [Amplasarea canalelor] În jurul unui oraş avem N bazine cu apă ce
trebuiesc unite între ele prin canale. Fiecare bazin poate fi unit prin
câte un canal cu mai multe bazine. Perechile de bazine ce vor fi unite
sunt date într-o listă. Un canal poate trece doar prin interiorul sau
exteriorul cercului format de bazine. Se cere modul de amplasare al
fiecărui canal.
3. Se dau numerele întregi nenule a1, a2, …, an şi b1, b2, …, bm cu n ≥
m. Să se determine o submulţime {x1, x2, …, xm} a mulţimii {a1, a2,
…, an} care să maximizeze expresia E = b1x1 + b2x2 + … + bmxm.
4. Într-un depozit al monetăriei statului sosesc n saci cu monezi. Se
cunoaşte numărul de monezi din fiecare sac şi se doreşte mutarea
monezilor dintr-un sac în altul în aşa fel încât în fiecare sac să apară
acelaşi număr de monezi. Scrieţi un program care rezolvă problema
efectuând un număr minim de mutări.
5. Fie n şiruri ordonate crescător S1, S2, …, Sn cu lungimile L1, L2, …,
Ln. Să se interclaseze cele n şiruri obţinându-se un singur şir crescător
de lungime L1 + L2 + … + Ln cu un număr minim de comparaţii între
elementele şirurilor.
6. Fie X = {x1, x2, …,xn} o mulţime de numere reale. Să se detmine o
mulţime de cardinal minim de intervale de lungime 1 a căror reuniune
să includă mulţimea X.
7. Se cunosc poziţiile oraşelor unei ţări date prin coordonatele lor. Să
se determine configuraţia unei reţele telefonice astfel încât toate
oraşele să fie conectate la reţea şi costul reţelei să fie minim.
8. Se dau n şi k, naturale, k≤n. Să se construiască un tablou n×n care
îndeplineşte simultan condiţiile:
♦ conţine toate numerele de la 1 la n2 o singură dată;
♦ pe fiecare linie numerele sunt aşezate în ordine crescătoare, de la
stânga la dreapta;
♦ suma elementelor de pe coloana k să fie minimă.
9. Un instructor de schi trebuie să distribuie n perechi de schiuri la n
elevi începători. Descrieţi un algoritm care să facă distribuirea în aşa
124
fel încât suma diferenţelor absolute dintre înălţimea elevului şi
lungimea schiurilor să fie minimă.
10. Se dă un polinom P(X) cu coeficienţi întregi. Să se afle toate
rădăcinile raţionale ale polinomului.
11. Se dau n puncte în plan prin coordonatele lor numere întregi. Să se
construiască, dacă este posibil, un poligon convex care să aibă ca
vârfuri aceste puncte.
12. Fiind dată o hartă cu n ţări, descrieţi un algoritm euristic care să
determine o modalitate de colorare a hărţii astfel încât două ţări care
se învecinează să fie colorate diferit.
13. Descrieţi un algoritm euristic care să determine o modalitate prin
care un cal aflat în colţul stânga-sus să străbată întreaga tablă de şah
fără a trece de două ori prin aceeaşi poziţie.
14. Descrieţi un algoritm euristic care să schimbe o sumă S dată
folosind un număr minim de monete având valorile v1, v2, …, vn.
3.4. Metoda backtracking
3.4.1.Prezentarea metodei
Această tehnică se foloseşte la rezolvarea problemelor a căror soluţie
se poate reprezenta sub forma unui vector S = x1x2...xn cu x1 ∈ S1, x2
∈ S 2, …, xn ∈ S n, iar mulţimile S1, S2, …, Sn, care pot coincide, sunt
mulţimi finite ordonate liniar (pentru orice element, cu exceptia
ultimului este cunoscut succesorul). Pentru fiecare problemă concretă
sunt precizate relaţiile dintre componentele vectorului care memorează
soluţia, numite condiţii interne. Mulţimea S = S1 × … × S1 se numeşte
spaţiul soluţiilor, iar elementele produsului cartezian care satisfac şi
condiţiile interne se numesc soluţii rezultat. Metoda evită generarea
tuturor combinaţiilor completând pe rând componentele vectorului
soluţie cu valori ce îndeplinesc condiţiile de continuare, scurtându-se
astfel timpul de calcul.
Vectorul x este privit ca o stivă, lui xk nu i se atribuie o valoare
decât după ce x1, …, xk-1 au primit valori. La început xk este iniţializat
la o valoare (cu ajutorul unei funcţii init) al cărei succesor este primul
element din Sk. Cu ajutorul unei funcţii succesor xk ia valoarea
primului element din Sk. După ce xk a primit o valoare, nu se trece
direct la atribuirea unei valori lui xk+1 ci se verifică mai întâi anumite
condiţii de continuare referitoare la x1, …, xk cu ajutorul unei funcţii
valid de tip logic. Dacă aceste condiţii sunt satisfăcute se verifică dacă
s-a obţinut o soluţie caz în care se trece la afişarea acesteia.
125
Neîndeplinirea condiţiilor de continuare exprimă faptul că oricum am
alege xk+1, …, xn, nu vom ajunge la o soluţie. În acest caz se face o
nouă alegere pentru xk sau, dacă Sk a fost epuizat, se micşorează k cu o
unitate şi se încearca o nouă alegere pentru xk (k >0) din restul
elementelor lui Sk încă nealese folosind funcţia succesor. Ca urmare se
trece la atribuirea unei valori lui xk+1 doar dacă sunt îndeplinite
condiţiile de continuare.
Algoritmul se termină în momentul în care au fost luate în calcul
toate elementele mulţimii S1.
Metoda backtracking poate fi descrisă prin următoarea proce-
dură (în varianta iterativă):
k := 1; init(k, st);
while k > 0 do begin
repeat
succesor(as, st, k);
if as then valid(ev, st, k);
until (not as) or (as and ev);
if as if solutie(k) then tipar
else begin k := k + 1; init(k, st) end
else k := k – 1;
end;
Rezolvarea problemelor prin această metodă necesită un timp mare de
execuţie, motiv pentru care metoda este recomandată numai în
cazurile în care spaţiul soluţiilor este destul de redus, sau dacă nu se
cunoaşte un alt algoritm mai rapid.
Metoda admite şi o variantă recursivă în care stiva nu este
gestionată explicit de programator. În continuare este dată forma
generală a procedurii backtracking în variantă recursivă (care se va
apela cu Back(1)):
procedure Back(k);
var i:integer;
begin
if solutie(k) then tipar(x)
else begin
init(k,x);
while succesor(x,k) do
begin x[k]:=i; if valid(x,k) then Back(k+1) end;
end
end;
126
3.4.2. Probleme rezolvate
R3.4.1. [Permutări] Se dă un număr n ∈ N, se cere să se genereze
toate permutările mulţimii {1, 2, …,n}.
Rezolvare:
program permutari;
uses crt;
type stack = array[1..25] of integer;
var st: stack;
n:integer; k:integer;
as, ev: boolean;
127
R3.4.2. [Descompunere ca sumă de numere prime] Să se descompună
un număr natural n în toate modurile posibile ca sumă de numere
prime.
Rezolvare:
program desc_prime;
var Prime, x :array[1..100] of integer;
n,k,i,p,S:integer;
function Prim(nr:integer):boolean;
var i:integer;
begin
Prim:=true; i:=2;
while i*i <= nr do
if nr mod i = 0 then
begin
Prim:=false; break;
end
else inc(i);
end;
procedure Tipar;
var i:integer;
begin for i:=1 to k do write(Prime[x[i]],' '); writeln end;
begin
write('n = '); readln(n);
p:=0;
for i:=2 to n do if Prim(i) then
begin inc(p); Prime[p]:=i end;
S:=0;
k:=1; x[k]:=0;
while k>0 do begin
inc(x[k]);
if (x[k] <= p) and (S + Prime[x[k]] <= n) then
if S + Prime[x[k]] = n then Tipar
else begin
inc(S,Prime[x[k]]); inc(k); x[k] := x[k-1]-1
end
else begin dec(k); Dec(S,Prime[x[k]]); end
end
end.
128
R3.4.3. [Problema damelor] Pe o tablă de şah trebuie aşezate opt
dame astfel încât să nu existe două dame pe aceeaşi linie, coloană sau
diagonală. Problema se generalizează imediat pentru n dame pe o
tablă cu n linii şi n coloane. Să se determine toate soluţiile.
Rezolvare :
#include <stdio.h>
#include <conio.h>
#include <math.h>
typedef int stack[25];
stack st;
int n;
void tipar(){
int j;
for(j = 0; j < n; j++) printf("%d ", st[j]);
printf("\n");
}
void dame(int k){
int i,j, valid;
if (k==n) tipar();
else for(i = st[k]+1; i <= n; i++) {
st[k] = i; valid = 1;
for(j = 0; j < k; j++)
if ((st[j]==st[k])||(abs(st[k]-st[j])==k-j)) valid = 0;
if (valid ==1) dame(k+1);
}
st[k] = 0;
}
void main(){
int i;
printf("n = "); scanf("%d",&n);
for(i = 0; i < n; i++) st[i]=0;
dame(0);
getch();
}
R3.4.4. [Problema colorării hărţilor] Fiind dată o hartă cu n ţări, se
cer toate soluţiile de colorare a hărţii utilizănd un număr minim de
culori, astfel încât două tări cu frontieră comună să fie colorate
diferit. Menţionăm că este demonstrat faptul că sunt suficiente 4
culori pentru a colora orice hartă.
129
Rezolvare:
program Culori;
uses crt;
type stack = array[1..25] of integer;
var st: stack;
i,j,k,n:integer;
as, ev: boolean;
a:array[1..25,1..25] of integer;
procedure init(k:integer;var st: stack);
begin st[k]:=0 end;
procedure succesor(var as:boolean; var st: stack; k:integer);
begin
if st[k] < 4 then begin st[k] := st[k] + 1; as := true end
else as:=false;
end;
procedure valid(var ev:boolean; st: stack; k:integer);
var i:integer;
begin
ev:=true;
for i:=1 to k-1 do if (st[k]=st[i]) and (a[i,k]=1) then ev:= false;
end;
function solutie(k:integer) :boolean;
begin solutie:=(k=n) end;
procedure tipar;
var i:integer;
begin for i:=1 to n do write(st[i],' '); writeln end;
begin
write (' n = '); readln(n);
for i:=1 to n do for j:=1 to i-1 do
begin write('a[',i,',',j,']= '); readln(a[i,j]); a[j,i]:=a[i,j] end;
k:=1; init(k,st);
while (k>0) do
begin repeat
succesor (as, st, k) ; if as then valid(ev,st,k);
until (not as) or (as and ev) ;
if as then if solutie(k) then tipar
else begin k:=k+1; init(k,st) end
else k:=k-1;
end;
end.
130
R3.4.5. [Săritura calului] Se consideră o tablă de şah n x n şi un cal
plasat în colţul din stânga sus. Se cere să se afişeze toate posibilităţile
de mutare a calului astfel încât să treacă o singură dată prin fiecare
pătrat al tablei.
Rezolvare:
#include <stdio.h>
#include <conio.h>
typedef int tabla[25][25];
int linT[8] = {-1,+1,+2,+2,+1,-1,-2,-2};
int colT[8] = {+2,+2,+1,-1,-2,-2,-1,+1};
tabla tab;
int n;
void tipar(){
int i,j;
for(i = 0; i < n; i++){ printf("\n");
for(j = 0; j < n; j++) printf("%3d", tab[i][j]);
}
printf("\n"); getch();
}
void cal(int lin, int col, int k){
int i,lin2,col2;
if (tab[lin][col]) return;
k++;
tab[lin][col]=k;
if (k==n*n) tipar();
else for (int i = 0; i < 8; i++){
lin2 = lin + linT[i];
col2 = col + colT[i];
if (lin2>=0 && lin2<n && col2>=0 && col2<n)
cal(lin2,col2,k);
}
tab[lin][col] = 0;
}
void main(){
int i,j;
printf("n = "); scanf("%d",&n);
for(i = 0; i < n; i++) for(j = 0; j < n; j++) tab[i][j]=0;
cal(0,0,0);
printf("\n%d solutii",t);
}
131
3.4.3. Probleme propuse
1. Se dau numerele naturale n şi k, să se genereze toate
aranjamentele (funcţiile injective) de elemente din mulţimea {1, 2,
…, n} luate câte k.
2. Fie două numere naturale n şi k cu n ≥ k, se cere să se genereze
toate submulţimile (combinările) de k elemente din mulţimea {1,
2, …,n}.
3. Se dau mulţimile A1 = {1, 2, …, p1}, A2 = {1, 2, …, p2}, …, An =
{1, 2, …, pn} se cere să se genereze produsul cartezian al
mulţimilor A1, A2, …, An.
4. Să se descompună un număr natural n în toate modurile posibile
ca sumă de numere naturale.
5. Se consideră mulţimea {1, 2, …, n}. Se cer toate partiţiile acestei
mulţimi.
6. Se dă o sumă S şi n tipuri de monede având valorile v1, v2, …, vn
lei. Se cer toate modalităţile de plată a sumei S utilizând aceste
monede.
7. Considerându-se o tablă de şah de dimensiuni n × n, să se
determine toate modalităţile de amplasare a n ture pe această tablă
în aşa fel încât să nu se atace între ele.
8. Un întreprinzător ce dispune de un capital C trebuie să leagă
dintre n oferte la care trebuie avansate fonfurile fi şi care aduc
profiturile pi pe acelea pe care le poate onora cu capitalul de care
dispune şi care îi aduc profitul total maxim.
9. Să se determine toate delegaţiile de n persoane din care p femei
care se pot forma din t persoane din care v femei.
10. Avem la dispoziţie 6 culori: alb, negru, roşu, albastru, verde,
galben. Să se genereze toate steagurile ce se pot forma cu trei
culori diferite având la mijloc alb sau negru.
11. Un comis-voiajor trebuie să viziteze un număr de n oraşe şi să
revină în oraşul de plecare. Cunoscând legăturile dintre oraşe se
cere să se afişeze toate drumurile posibile pe care poate să le
parcurgă comis-voiajorul ştiind că nu trebuie să treacă de două ori
prin acelaşi oraş.
12. Într-un grup de persoane fiecare persoană se cunoaşte pe sine şi
cunoaşte eventual şi alte persoane din grup. Să se determine toate
modurile în care cele N persoane se pot repartiza în echipe astfel
încât orice persoană din grup să fie cunoscută de cel puţin un
membru al fiecărei echipe.
132
13. Cei doi fii ai unei familii moştenesc prin testament, în mod egal, o
avere formată din monede având ca valori numere întregi pozitive.
O condiţie din testament cere ca fraţii să împartă monezile în
două părţi având valori egale pentru a intra în posesia lor, altfel
suma va fi donată unei biserici. Scrieţi un program care să îi ajute
pe cei doi fraţi să intre în posesia moştenirii.
14. Pe malul unui râu se găsesc c canibali şi m misionari. Ei urmează
să treacă râul cu o barcă cu două locuri. Dacă pe unul dintre
maluri se vor afla mai mulţi canibali decât misionari aceştia din
urmă vor fi mâncaţi de canibali. Se cere un program care să
afişeze toate modalităţile de trecere a râului în care misionarii să
nu fie mâncaţi.
15. Pentru elaborarea unui test de aptitudini avem un set de n
întrebări, fiecare fiind cotată cu un număr de puncte. Să se
elaboreze toate chestionarele având între a şi b întrebări distincte,
fiecare chestionar totalizând între p şi q puncte. Întrebările sunt
date prin număr şi punctaj.
16. 2n + 1 persoane participă la discuţii (masă rotundă) care durează n
zile. Să se găsească variantele de aşezare la masă astfel ca o
persoană să nu aibă în două zile diferite acelaşi vecin.
17. Să se determine 5 numere de câte n cifre fiecare cifră putând fi 1
sau 2, astfel încât oricare dintre cele 5 numere să coincidă în m
poziţii şi să nu existe nici o pozitie care să conţină aceeaşi cifră în
toate cele 5 numere.
18. Să se genereze o secvenţă binară de lungime 2n+n+1 astfel încât
orice două secvente consecutive de n biti să fie diferite.
19. Se dau x1, x2, …, xn numere naturale cu cel mult 9 cifre şi n ≤ 100.
Fiecare număr xi este reprezentat în baza bi (2 ≤ bi ≤ 10) care nu
este cunoscută. Să se gasească baza bi pentru fiecare număr xi
astfel încât intervalul [a, b] în care sunt cuprinse cele n numere
(după transformarea în baza 10) să fie de lungime minimă.
20. Numărul 123456789 înmulţit cu 2, 4, 7 sau 8 dă ca rezultat tot un
număr de nouă cifre distincte (fără 0). Această proprietate nu
funcţionează pentru numerele 3, 6 sau 9. Există totuşi multe
numere de nouă cifre distincte (fără 0) care înmulţite cu 3 au
aceeaşi proprietate. Să se listeze toate aceste numere în care
ultima cifră este 9.
21. Să se dispună pe cele 12 muchii ale unui cub toate numerele de la
1 la 12, astfel încât suma numerelor aflate pe muchiile unei feţe să
fie aceeaşi pentru toate feţele.
133
22. Toate oraşele unei ţări sunt legate la o reţea de linii feroviare.
Două oraşe i şi j pot fi legate prin cel mult o legătură directă prin
care circulă un singur tren pe zi între orele p(i, j) şi s(i, j). Dacă se
dau două oraşe A şi B, să se afişeze traseul, staţiile de schimbare a
trenurilor şi timpii de aşteptare în aceste staţii astfel încât durata
totală a călătoriei să fie minimă.
23. Configuraţia unui teren este specificată printr-o grilă gen tablă de
şah de dimensiune n×n, fiecare careu având o anumită înălţime.
Într-un careu precizat al grilei se plasează o minge. Ştiind că
mingea se poate deplasa într-unul din cele maxim 8 careuri vecine
doar dacă acesta are o cotă strict mai mică, să se genereze toate
trasele pe care le poate urma mingea pentru a părăsi terenul.
24. Un cal şi un rege se află pe o tablă de şah. Unele câmpuri ale
tablei sunt "arse", poziţiile lor fiind cunoscute. Calul nu poate
călca pe câmpuri "arse", iar orice mişcare a calului face ca
respectivul câmp să devină "ars". Să se afle dacă există o
succesiune de mutări permise (cu restricţiile de mai sus), prin care
calul să poată ajunge la rege şi să revină la poziţia iniţială. Poziţia
iniţială a calului, precum şi poziţia regelui sunt considerate
"nearse".
25. Fie o matrice n x m cu valori de 0 şi 1. Dându-se o poziţie iniţială
(i,j) să se găsească toate ieşirile din matrice mergând doar pe
elemente cu valoarea 1.
26. O fotografie alb-negru este dată printr-o matrice cu valori 0 şi 1.
Fotografia prezintă unul sau mai multe obiecte. Punctele fiecărui
obiect sunt marcate cu 1. Se cere un program care să calculeze
numărul de obiecte din fotografie.
27. Se dă o matrice binară în care elementele cu valoarea 1
delimitează o suprafaţă marcată cu elemente de zero. Dându-se
coordonatele unui punct în cadrul matricei să se “coloreze”
suprafaţa în interiorul căreia cade punctul.
28. Se dau n puncte albe şi n puncte negre în plan prin perechi (i,j) de
numere întregi. Fiecare punct alb se va uni cu un singur punct
negru asttfel încăt segmentele formate să nu se intersecteze. Să se
găsească o soluţie ştiind ca oricare 3 puncte sunt necoliniare.
29. Se dau n puncte în plan prin perechi (i,j) de numere întregi. Să se
selecteze 4 puncte ce reprezintă colţurile pătratului care cuprinde
numărul maxim de puncte din cele n puncte date.
134
30. Se dă un cuvânt si o matrice de caractere de dimensiune m x n. Să
se găsească în matrice prefixul de lunginme maximă al cuvântului
dat.
31. Se dă un număr natural par n. Să se afişeze toate şirurile de n
paranteze care se închid corect.
32. Se consideră o bară de lungime n şi k repere de lungimi l1, l2,…,
lk. Din bară trebuiesc tăiate bucăţi de lungimea reperelor date,
astfel încât să avem cel puţin câte o bucată de lungime li cu i =
1..k şi pierderile să fie nule.
33. Se consideră un număr nelimitat de piese dreptunghiulare de
dimensiuni a × 2a. Piesele se vor folosi la pavarea fără fisuri a
unei zone rectangulare de dimensiuni ka × pa. Se cer toate
soluţiile (reprezentare grafică).
program RucsacBB;
uses crt;
const max = 25;
type TObiect = record masa, profit:integer; nr:integer end;
PNod= ^Nod;
Nod = record
nivel,luat:integer;
p_estimat,profit,masa:integer;
tata,drept,stang:PNod;
end;
var n: integer;
obiect: array[1..max] of TObiect;
G, profitmax,masatotala:integer;
solutie:array[1..max] of 0..1;
137
procedure Sort;
var i,j:integer; aux:TObiect;
begin
for i:=1 to n-1 do for j:=i+1 to n do
if
(obiect[i].profit/obiect[i].masa < obiect[j].profit/obiect[j].masa)
then begin aux:= obiect[i]; obiect[i]:=obiect[j]; obiect[j]:=aux;
end;
end;
function H(pn:PNod):integer;
var i,k:integer; p,m:integer;
begin
p := pn^.profit; m := pn^.masa; k := pn^.nivel;
if m <= G then begin
for i:= k + 1 to n do if m + obiect[i].masa <= G then
begin
p := p + obiect[i].profit; m := m + obiect[i].masa
end;
H := p
end
else H:=-1;
end;
procedure Branch;
var k:integer; nodc,stang,drept:PNod;
begin
k:=0; new(nodc); nodc^.tata:= nil; nodc^.nivel:=k;
nodc^.luat:=0; nodc^.masa:=0; nodc^.profit:=0;
repeat
inc(k); new(stang); new(drept);
nodc^.stang:=stang; nodc^.drept:=drept;
stang^.tata:=nodc; stang^.nivel:=k; stang^.luat:=0;
stang^.masa:=nodc^.masa; stang^.profit:=nodc^.profit;
stang^.p_estimat:= H(stang); drept^.tata:=nodc;
drept^.nivel:=k; drept^.luat:=1;
drept^.masa:=nodc^.masa + obiect[k].masa;
drept^.profit:=nodc^.profit + obiect[k].profit;
drept^.p_estimat:=H(drept);
if stang^.p_estimat > drept^.p_estimat
then nodc:=stang else nodc:=drept;
until k=n;
138
profitmax := nodc^.profit; masatotala := nodc^.masa;
while nodc^.tata<>nil do begin
solutie[nodc^.nivel]:=nodc^.luat; nodc:=nodc^.tata;
end
end;
var i:integer;
begin {main}
write('Capacitatea rucsacului = '); readln(G);
write('Numarul obiectelor = '); readln(n);
for i:= 1 to n do
begin
write('Masa[',i ,'] = '); readln(obiect[i].masa);
write('Profitul[',i ,'] = '); readln(obiect[i].profit);
obiect[i].nr := i;
end;
Sort;
Branch;
writeln('Solutie:');
for i:= 1 to n do if solutie[i]=1 then write(obiect[i].nr,' ');
writeln;
writeln('Profitul obtinut = ', profitmax);
writeln('Masa totala = ', masatotala);
readln;
end.
R3.5.2. [Jocul Perspico] Se consideră o tablă cu 4 x 4 căsuţe, fiecare
căsuţă conţine un număr între 1 si 15 si o căsută conţine zero (este
liberă). Ştiind că 0 îşi poate schimba poziţia cu orice numâr natural
aflat deasupra, la dreapta, la stânga sau jos, în raport cu poziţiâ în
care se află numărul 0, se cere să se precizeze şirul de mutări prin
care se poate ajunge de la o configuraţie iniţială dată la o confi-
guraţie finală. Se cere de asemenea ca acest sir să fie optim, în sensul
că trebuie să se ajungă la configuraţia finalâ într-un număr minim de
mutări.
Rezolvare:
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#define MAX 4
#define maxop 4
139
typedef struct Nod{
char conf[MAX][MAX];
int h, g;
struct Nod *down, * up;
}Nod, *PNod;
PNod New(PNod p){
PNod pnod = (PNod) malloc( sizeof(Nod) );
if (pnod==NULL){
printf("\nNot enough memory !\n");
exit(0);
}
*pnod = *p;
return pnod;
}
void Insert(PNod * list, PNod pnod){
pnod->down = *list; *list = pnod;
}
void RemoveAll(PNod *list){
PNod p;
while(*list){
p = *list; *list = (*list)->down;free(p);
}
}
PNod Expand(PNod pnod){
int i, j, k, ii, jj;
static int lin[maxop] = {-1, 0, 1, 0};
static int col[maxop] = { 0, 1, 0,-1};
PNod list = NULL; PNod newNod = NULL;
for(i=0; i < MAX; i++) for(j=0; j < MAX; j++)
if (pnod->conf[i][j]==0) ii=i,jj=j;
for(k = 0; k < maxop; k++){
i = ii + lin[k]; j = jj + col[k];
if(i >= 0 && i < MAX && j >= 0 && j < MAX){
newNod = New(pnod);
newNod->conf[ii][jj] = newNod->conf[i][j];
newNod->conf[i][j] = 0; Insert(&list,newNod);
}
}
return list;
}
140
int Equals(PNod n1, PNod n2){
int i, j;
if (n1->h != n2->h) return 0;
for (i = 0; i < MAX; i++) for (j = 0; j < MAX; j++)
if (n1->conf[i][j] != n2->conf[i][j]) return 0;
return 1;
}
PNod Extract(PNod * list, PNod p){
PNod temp = *list, spy = *list;
if (p==NULL || p == *list){ *list = (*list)->down; return temp;}
while(temp != p){ spy = temp; temp = temp->down;}
spy->down = temp->down;
return temp;
}
void PrintNod(PNod pnod){
int i,j;
for(i = 0; i < MAX; i++){ printf("\n|");
for(j = 0; j < MAX; j++) printf("%3d", pnod->conf[i][j]);
printf(" |");
}
printf("\nApasati orice tasta ...”); getch();
}
void Print(PNod pnod){
if (pnod->up) Print(pnod->up); PrintNod(pnod);}
PNod Choice(PNod list){
int f, min = 32000; PNod pmin = NULL;
while (list){
f = list->h + list->g; if ( f < min ){pmin = list; min = f;}
list=list->down;}
return pmin;
}
void ComputeH(PNod t, PNod fin){
int i, j, k, r, s; t->h = 0;
for(i = 0; i < MAX; i++) for(j = 0; j < MAX; j++)
for(r = 0; r < MAX; r++) for(s = 0; s < MAX; s++)
if (t->conf[i][j] == fin->conf[r][s]) t->h += abs(r-i) + abs(s-j);
}
PNod Search(PNod list, PNod pnod){
while (list && !Equals(list,pnod)) list = list->down;
return list;}
141
void Branch(Nod *in, Nod *fin){
PNod Open = NULL; PNod Close = NULL;
PNod TempList = NULL; PNod theOne, temp, found;
PNod initial = New(in); Pnod final = New(fin);
int ok = 0; initial->g = 0;
ComputeH(initial,final); final->h = 0; Insert(&Open,initial);
while(Open){ theOne = Choice(Open); Extract(&Open,theOne);
Insert(&Close,theOne);
if (Equals(theOne, final)){ok = 1; break;}
TempList = Expand(theOne);
while(TempList){
temp = Extract(&TempList,NULL);
temp -> g = theOne->g + 1;
if( found = Search(Open, temp) ){
if(temp->g < found->g){
found->g = temp->g; found->up = theOne;}
free(temp);
}
else if( found = Search(Close, temp) ){
if(temp->g < found->g){
found-> g = temp->g; found->up = theOne;
Extract(&Close, found);
Insert(&Open, found);}
free(temp);
}
else{ temp->up = theOne; ComputeH(temp,final);
Insert(&Open,temp);}
}
}
if (ok){ printf("\nSolutie:\n"); Print(theOne);}
else printf("Nu am avem solutii !");
RemoveAll(Open); RemoveAll(Close);
}
void main(){
Nod in = {{ 5, 1, 3, 4, 9, 7, 8, 0, 6, 2, 10, 11,
13, 14, 15, 12}, 0, 0, NULL,NULL};
Nod fin ={{ 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,
13,14,15, 0},0,0, NULL,NULL};
clrscr(); Branch(&in,&fin); getch();
}
142
3.5.3. Probleme propuse
1. [Generalizare] Să se rezolve problema Perspico pentru o tablă de
dimensiuni n x n cu numere de la 1 la n2-2 şi cu două zerouri (locuri
libere).
2. [Diamante] Se dă o tablă sub formă de cruce pe care sunt aşejate 32
de piese de diamant (◊) aşa cum se poate observa în figura de mai jos.
Poziţia din centru este liberă. O piesă se poate muta doar sărind
peste o altă piesă într-un loc liber, numai pe orizontală sau pe verticală
iar piesa peste care se sare trebuie luată. Se cere să se gasească un şir
de mutări astfel încât (să luăm cât mai multe piese de diamant)
pornind de la configuraţia iniţială să se ajungă la o configuraţie finală
care să conţină numai o singură piesă şi aceasta să se afle în centru.
◊ ◊ ◊
◊ ◊ ◊
◊ ◊ ◊ ◊ ◊ ◊ ◊
◊ ◊ ◊ ◊ ◊ ◊ ◊
◊ ◊ ◊ ◊ ◊ ◊ ◊
◊ ◊ ◊
◊ ◊ ◊
A B C D E F G
1
2 O O O
3 O O O
4 O O X X
5 X X X
6 X X X
7
144
Tehnici avansate de programare - 2009
Probleme propuse
1. Colectia 2008
2. Probleme rezolvabile folosind metoda backtracking
3. Probleme diverse
Bibliografie
1. G. Albeanu, Algoritmi si limbaje de programare, Editura FRM, 2000.
(Capitolul 5).
2. G. Albeanu (coord.), L. Rapeanu, L. Radu, A. Averian, Tehnici de programare,
Editura FRM, 2003 (capitolele 2 si 3). Acest material este disponibil in
sectiunea Biblioteca virtuala.
1.
a. q, r, p c. r, q, p
b. p, q, r d. p, q, r
2.
a. Q, R, P c. P, R, Q
b. R, Q, P d. P, Q, R
3.
a. Q -> urm -> urm == P
b. P -> urm == Q
c. P -> urm -> urm == Q
d. Q -> urm == P -> urm -> urm
4.
a. P -> urm -> urm == Q -> urm
b. P -> urm -> urm == Q
c. Q -> urm -> urm -> urm == P -> urm
d. Q -> urm -> urm == P -> urm
5.
a. P -> URM = Q
b. Q -> URM = P
c. Q -> URM -> URM = P
d. P -> URM -> URM = Q
6.
a. c.
b. d.
7. Intr-o lista simplu inlantuita alocata dinamic fiecare element retine in campul nr un numar intreg si
in campul urm adresa urmatorului element din lista. Stiind ca variabila p contine adresa primului element din
lista si variabila t este de acelasi tip cu variabila p, stabiliti care dintre urmatoarele secvente elibereaza
intreaga zona de memorie ocupata de elementele listei.
a. while(p) {t = p; p = p->urm; free(p);}
b. while(p) {t = p; p = p->urm; free(t);}
c. while(p) {t=p; t=t->urm; free(t);}
d. free(p);
8. Intr-o lista liniara simplu inlantuita, fiecare element retine in campul urm adresa urmatorului nod din
lista, iar in campul inf un numar intreg. Adresa primului element al listei este retinuta in variabila p. Daca in
lista sunt memorate, in aceasta ordine, numerele: 5, 9, 3, si 6 (6 fiind ultimul element), in urma executarii
secventei de instructiuni (p indica, initial, nodul cu numarul 5):
{ q = p -> urm -> urm; p->urm -> urm = q -> urm; q->urm = p -> urm; p -> urm = q;}
in lista vor fi in ordine numerele:
a. 9, 5, 3, 6
b. 5, 9, 6, 3
c. 5, 3, 6, 9
d. 5, 3, 9, 6
9. O lista liniara simplu inlantuita formata dintr-un numar impar de cel putin 5 noduri are adresa
primului nod memorata in variabila prim. In campul urm al fiecarui nod al listei se memoreaza adresa
urmatorului element din lista. Adresa carui nod va fi memorata in variabila p, dupa executarea secventei de
program:
{p = prim; q = prim;
while(q->urm) {
q = q -> urm -> urm;
p = p -> urm;
}
}
a. penultimul nod al listei
b. nodul aflat in mijlocul listei
c. ultimul nod al listei
d. nodul al treilea din lista
10. Intr-o lista simplu inlantuita, alocata dinamic, fiecare element retine in campul next adresa
urmatorului nod din lista, iar in campul info un numar intreg. Adresa primului element al listei este
memorata in variabila prim. Se stie ca lista are cel putin 3 noduri. Care dintre urmatoarele secvente de
instructiuni elimina corect penultimul element al listei?
a. {
p = prim; do p = p->next; while(p->next->next->next);
p->next=p->next->next;
}
b. {
p = prim;
while (p->next->next->next) p = p->next;
p->next=p->next->next;
}
c. {
p = prim;
while (p->next->next) p = p->next;
p->next=p->next->next;
}
d. prim -> next = prim->next -> next;
11. Intr-o lista liniara, simplu inlantuita, alocata dinamic, fiecare element retine in campul next
adresa urmatorului nod din lista, iar in campul info in numar intreg. Adresa primului element al listei este
memorata in variabila prim. Lista contine cel putin 3 noduri. Care este efectul executarii urmatoarei secvente
de program
{
p = prim; q = p->next -> next;
while ( q-> next) {p = p->next; q = q-> next;}
p -> next = q;
}
adresa elementului urmator din lista. Daca p retine adresa primului element, iar lista are cel putin doua
elemente, care dintre urmatoarele secvente dee instructiuni sterge al doilea element al listei?
a. q = p->adru; p->adru = q -> adru; free(q);
b. p -> adru = p->adru -> adru; free (p->adru);
c. q = p-> adru; free(q); p ->adru = q->adru;
d. free(p->adru);
13 . O lista liniara simplu inlantuita alocata dinamic, in care fiecare element memoreaza in
campul nr un numar intreg, iar in campul urm adresa elementului urmator din lista, contine exact trei
elemente ale caror adrese sunt memorate in variabilele p, q si r. Stiind ca q -> nr == 3, p -> nr == 5, r -> nr
== 8, q -> urm != NULL, p -> urm == NULL si r -> urm == q, care este ordinea numerelor din lista?
a. 8, 3, 5
b. 5, 8, 3
c. 3, 8, 5
d. 5, 3, 8
14. Intr-o lista circulara simplu inlantuita alocata dinamic cu cel putin un element, fiecare
element retine in campul nr un numar intreg si in campul urm adresa urmatorului element din lista. Stiind ca
variabila p retine adresa unui element din lista si variabila t este de acelasi tip cu p, stabiliti care dintre
urmatoarele secvente afiseaza toate valorile memorate in nodurile listei, fiecare valoare fiind afisata exact
odata.
a. t = p;
while(t -> urm != p) {
printf(“%d “, t -> nr;
t = t->urm;}
b. t = p;
do{
printf(“%d “, t -> nr;}
t = t->urm;
}while(t != p);
c. t = p;
while(t != p) {
printf(“%d “, t -> nr;
t = t->urm;}
d. t = p->urm;
do{
printf(“%d “, t -> nr;}
t = t->urm;
}while(t != p);
15. Intr-o lista dublu inlantuita care incepe cu elementul memorat la adresa p si contine cel putin
4 elemente, fiecare element retine in campul urm adresa elementului urmator, in campul pre adresa
elementului precedent, iar in campul inf o valoare intreaga. Care dintre urmatoarele variante tipareste
valoarea celui de-al treilea element al listei?
a. printf(“%d “, p->urm -> urm -> pre -> inf);
b. printf(“%d “, p->urm -> urm -> urm -> pre -> inf);
c. printf(“%d “, p->urm -> urm -> urm);
d. printf(“%d “, p->urm -> urm);
16. Variabila p retine adresa unui element oarecare al unei liste circulare nevide alocata dinamic,
in care fiecare element memoreaza in campul nr un numar intreg, iar in campul urm adresa elementului
urmator. Care dintre urmatoarele variante tipareste toate elementele listei?
a. q = p; do{
printf(“%d”, q -> nr); q = q -> urm;
} while (q != p);
b. q = p; while (q -> urm != p){
printf(“%d”, q -> nr); q = q -> urm;
}
c. q = p; while (q != p){
printf(“%d”, q -> nr); q = q -> urm;
}
d. q = p->urm;
while (q != p){
printf(“%d”, q -> nr); q = q -> urm;
}
17. Se considera o coada in care initial au fost introduse, in aceasta ordine, elementele 1 si 2.
Daca se noteaza cu AD(x) operatia prin care se adauga informatia x in coada, si cu EL() operatia prin care se
elimina un element din coada, care este rezultatul executarii secventei: EL(); Ad(3); EL(); AD(4); AD(5);?
a. 1, 4, 5
b. 5, 4, 2
c. 3, 4, 5
d. 5, 4, 3
18 Se considera o stiva in care initial au fost introduse, in aceasta ordine, valorile 1 si 2. Daca se
noteaza cu PUSH(x). operatia prin care se insereaza valoarea x in varful stivei si POP() operatia prin care se
extrage elementul din varful stivei, care este continutul stivei in urma secventei de operatii: POP(); PUSH(3);
POP(); PUSH(4); PUSH(5);
a. 5 b. 5 c. 2 d. 1
4 4 3 4
3 1 5 5
este adresa nodului ce contine primul numar 2 (fiecare nod are un camp nr ce contine numarul intreg si un
camp urm care indica adresa elementului urmator din lista). Prin executarea secventei
while (p -> nr > 0) {p -> nr = p -> nr -1; p = p -> urm;}
continutul listei, citit de la adresa de plecare va fi:
a. 0, 1, 0, 2,0
b. 1, 2, 1, 2, 0
c. 0, 1, 1, 2, 0
d. 0, 1, 0, 1, 0
unei liste liniare nevide dublu inlantuite. Elementele listei retin in campul urm adresa elementului urmator,
iar in campul prec adresa elementului anterior. Stabiliti care este numarul de noduri din lista daca p -> urm -
> urm si q -> prec -> prec indica acelasi nod al listei.
a. 4 c. 3
b. 5 d. 2
21. Se considera lista circulara simplu inlantuita ce contine celulele cu numerele 1, 2, 3, 4 (in
aceasta ordine). Fiecare element memoreaza in campul nr un numar intreg, iar in campul urm adresa
elementului urmator din lista. Variabila prim indica nodul ce contine numarul 1. Cate treceri sunt necesare
pentru ca toate elementele din lista sa ajunga egale. Definim prin trecere prelucrarea data de secventa
urmatoare:
p = prim;
do {if(p->nr > prim->nr) p->nr = p->nr -1; p = p -> urm;}
while (p != prim);
a. 5 c. 3
b. 2 d. 4
22 . Intr-o lista circulara simplu inlantuita, p este adresa unui nod din lista si campul next
memoreaza pentru fiecare nod adresa nodului urmator din lista. Pentru a numara elementele listei vom scrie
secventa (variabila q este de acelasi tip cu variabila p):
a. q = p; k = 1; while(q -> next != p) {k++; q = q -> next;}
b. q = p; k = 1; do{ q = q -> next; k++; } while(q ==p);
c. q = p; k = 1; while(q!=p) {k++; q = q->next;}
d. k=0; do{p=p->next; k++;} while (p!=NULL);
23 . Se considera o stiva alocata dinamic care are cel putin 10 elemente. Variabila vf memoreaza
adresa de inceput a stivei si orice element al stivei memoreaza in campul info un numar intreg, iar in campul
next adresa nodului urmator. Se considera seceventa de program:
while (vf && vf -> info %2 == 0) {
aux = vf;
vf = aux-> next;
free (aux);
}
Daca in urma executarii secventei de program, variabila vf are valoarea NULL, atunci:
a. Primul element memorat in stiva este par, celelalte fiind numere impare.
b. In stiva nu s-a memorat nici un numar impar.
c. Ultimul element memorat in stiva este par, celelalte elemente fiind numere impare.
d. In stiva nu s-a memorat nici un numar par.
elimina elementul numerotat cu 3, apoi se elimina fiecare al treilea element al parcurgeri, numararea
continuandu-se cu succesorul elementului eliminat, pana cand lista va mai contine un singur element. Care
va fi numarul de ordine al elementului ramas?
a. 2 c. 3
b. 7 d. 4
25 . Se considera o lista circulara dublu inlantuita ale carei noduri retin in campul st adresa
nodului anterior, iar in campul dr adresa nodului urmator din lista. Lista are cel putin doua elemente. Stiind
ca p retine adresa unui nod din lista, care este numarul de noduri din lista astfel incat relatia
p->st->st == p->dr sa fie adevarata?
a. 5 c. 2
b. 3 d. 4
26 . Se considera lista dublu inlantuita cu noduri care contin in campul inf (ce retine un n umar
27 . Se considera lista dublu inlantuita cu noduri care contin in campul inf (ce retine un n umar
29 . Intr-o lista simplu inlantuita circulara, fiecare element retine in campul adr adresa
elementului urmator din lista. Daca p si q sunt adresele a doua elemente distincte din lista astfel incat sunt
satisfacute conditiile p == q -> adr si q == p -> adr. Atunci lista are
a. un numar impar de elemente c. cel putin 3 elemente
b. exact 2 elemente d. exact 1 element
= 10, a[2] = 20, a[3] = 30, a[4] = 40, a[5] = 50. Daca cel de-al doilea element, incepand de la baza stivei este
10, atunci primul element care iese din stiva este:
a. a[6] c. a[5]
b. a[1] d. a[0]
31 . Intr-o lista circulara simplu inlantuita, cu cel putin un element, fiecare nod retine in campul
adr adresa elementului urmator din lista. Daca p este o variabila care retine adresa primului element din lista,
iar q este o variabila care poate sa retina adresa unui element din lista, care dintre urmatoarele secvente de
instructiuni calculeaza in variabila nr, de tip int, numarul de elemente al listei?
a. nr = 0; q = p; while(q != p) {nr++; q = q -> adr;}
b. nr = 0; q = p; do {nr ++; q = q -> adr;} while (q != p);
c. nr = 0; q = p; do {nr ++; q = p -> adr;} while (q != p);
d. nr = 0; q = p; while (p != q){ nr ++; p = p -> adr;}
32 . Intr-o lista circulara simplu inlantuita fiecare element retine in campul adr adresa
elementului urmator din lista. Daca p reprezinta adresa unui element din lista atunci stabiliti care dintre
urmatoarele expresii are valoarea 1 daca si numai daca lista contine exact doua noduri.
a. p -> adr == p c. p -> adr -> adr == p
b. p -> adr -> adr == NULL d. p -> adr != NULL
33 . Se considera urmatoarea functie recursiva apelata numai pentru numere naturale nenule:
34 .
int j;
if (n>0) for (j=1; j<=n; j++) {printf(“%d”,j); f(n-1);}
}
Ce se afiseaza ca urmare a apelului f(2)?
a. 1122 c. 121
b. 112 d. 1121
35 .
if (n == 0) return 1;
else if (n == 1) return 4;
else return f(n-1) - f(n-2);
}
Stabiliti ce valoasre returneaza apelul f(7).
a. 1 c. -4
b. -3 d. 4
a. 3 c. 2
b. 1 d. 4
37 . Se considera definitia:
a. 50 c. 40
b. 45 d. 55
38 .
if(i<10) {
printf(“*”);
if (v[i] == i+1) star(i+2); else star(i+1);
}
}
Pentru care dintre declaratiile urmatoare, apelul star(0) produce 7 asteriscuri (stelute)?
a. int v[] = {1, 4, 3, 2, 1, 6, 5, 4, 3, 10};
b. int v[] = {3, 2, 1, 4, 3, 6, 7, 2, 9, 2};
c. int v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
d. int v[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
39 . Pentru o valoare naturala mai mare decat 1 memorata in variabila globala n, subprogramul
urmator afiseaza cel mai mare divizor al lui n, mai mic decat n, la apelul divi(n).
void divi(long i){
if ( ... == 0) printf(“%ld”, ...); else divi(i-1);
}
Cu ce expresii trebuie completate punctele de suspensie?
a. n % i si i c. n%(i-1)=0 si i
b. n% (i-1) si i-1 d. n%i si i-1
declarat global), M este multimea tuturor cifrelor nenule, iar functia tipar afiseaza valorile elementelot p[0],
p[1] si p[2], cu ce trebuie inlocuite simbolurile a, b si c in definitia functiei G astfel incat in urma apelului
G(0) sa se afiseze toate elementele produsului cartezian MxMxM?
void G(int k){
int i;
for (i = a; i<=b; i++) { p[k] = i; if (k == c) tipar(); else G(k+1);}
}
a. a = 0, b = 10, c = 3 c. a = 1, b = 9, c = 3
b. a = 1, b = 3, c = 9 d. a = 1, b = 9, c = 2
41 .
if (x != 0){
printf(“%d”, x %10);
ex(x/10);
}
}
a. 012 c. 021
b. 120 d. 21
42.
a. 230
Gasiti elementul f(20) din sirul definit prin relatia (f(n))2 = 8(f(n-1))2, unde f(0) = 2
c. 219
b. 220 d. 231
43 . Se considera relatia de recurenbta neomogena de ordinul intai f(n) - f(n-1) = 9n2, f(0) = 8,
b. d.
44
a.
. Se considera relatia de recurenta f(n) - 7f(n-1) = 9(5n), n > 0; f(0) = 3. Atunci f(n) =
c.
b. d.
45 .
a. (9n+3)7n
Solutia f(n) a relatiei de recurenta f(n) - 7f(n-1) = 9(7n), n>0, f(0) = 3, este
c. (9n+9)7n
b. (3n+9)7n d. (3n+3)7n
46 .
a. 3n-n3n-1
Solutia relatiei de recurenta f(n) = 6 f(n-1) - 9 f(n-2), n≥0, f(0) = 1, f(1) = 2 este f(n) =
c. 3n+1-n3n
b. 3n-1-n3n d. 3n+1-n3n-1
47
a.
. Solutia relatiei de recurenta f(n) = 2f(n-1) - 4f(n-2), n>1, f(0)=1, f(1) = 3 este f(n) =
c.
b. d.
si 1 cu proprietatea ca nu exista mai mult de doua cifre de 0 consecutive. Primele sase solutii generate sunt:
00100, 00101, 00110, 01001, 01010. Care este cea de-a opta solutie?
a. 01110 c. 01011
b. 01100 d. 01101
49 Un algoritm backtracking genereaza toate sirurile alcatuite din cate 5 cifre binare (0 si 1).
50 . Aplicand metoda backtracking pentru a genera toate permutarile celor n elemente ale unei
multimi, o solutie se memoreaza sub forma unui tablou unidimensional x1, x2, ..., xn. Daca sunt deja generate
valori pentru componentele x1, x2, ..., xk-1, iar pentru componenta xk (1 <k<n)au fost testate toate valorile
posibile si nu a fost gasita niciuna convenabila, atunci:
a. se incearca alegerea unei noi valori pentru componenta xk-1.
b. se incearca alegerea unei noi valori pentru componenta x1, oricare ar fi valoarea k.
c. se incheie algoritmul.
d. se incearca alegerea unei valori pentru componenta xk+1.
51 . Daca se utilizeaza metoda backtracking pentru a genera toate numerele naturale, in ordine
strict crescatoare, formate din 4 cifre pare distincte, care dintre numerele de mai jos trebuie, eliminate astfel
incat cele ramase sa reprezinte o succesiune de numere corect generate?
1) 2068; 2) 2084; 3) 2088; 4) 2468; 5) 2086; 6) 2406
a. numai 3)
b. atat 3) cat si 5)
c. atat 3) cat si 4)
d. numai 4)
52 . Se considera multimea {1, 7, 5, 16, 12}. Se genereaza prin metoda backtracking toate
submultimile sale formate din exact 3 elemente: primele patru solutii generate sunt, in ordine: {1, 7, 5}, {1,
7, 16}, {1, 7, 12}. Care dintre solutii trebuie eliminate din sirul urmator astfel incat cele ramase sa apara in
sir in ordinea generarii lor:
{1, 16, 12}, {5, 16, 12}, {7, 5, 16}, {7, 5, 12}
a. {1, 16, 12}
b. {5, 16, 12}
c. {7, 5, 16}
d. {7, 5, 12}
53 . Se considera algoritmul care genereaza in ordine strict crescatoare toate numerele formate cu
5 cifre distincte alese din multimea {1, 0, 5, 7, 9} in care cifra din mijloc este 0.Selectati numarul care
precede si numarul care urmeaza secventei de numere generate:
19075; 51079; 51097
a. 19057, 57019
b. 15079, 71059
c. 19057, 59071
d. 15097, 71095
54 . Daca pentru generarea tuturor submultimilor unei multimi A = {1, 2, ..., n} cu 1 ≤ n ≤ 10, se
utilizeaza un algoritm backtracking astfel incat se afiseaza in ordine, pentru n=3, submultimile {}, {1}, {2},
{3}, {1, 2}, {1,3}, {2,3}, {1, 2, 3}, atunci, utilizand exact acelasi algoritm pentr n = 4, in sirul submultimilor
generate, solutia a 7-a va fi:
a. {1,3}
b. {4}
c. {1,2,3}
d. {1,4}
55 . Produsul cartezia {1,2,3}x{2,3} este obtinut cu ajutorul unui algoritm backtracking care
genereaza perechile (1,2), (1,3), (2,2), (2,3), (3,2) si (3,3). Care este numarul perechilor obtinute prin
utilizarea aceluiasi algoritm la generarea produsului cartezian {1, 2, 3, 4}x{2, 3, 4}?
a. 12 c. 81
b. 10 d. 6
56 . Se genereaza toate sirurile strict crescatoare de numere naturale nenule mai mici sau egale cu
4, avand primul termen 1 sau 2, ultimul termen 4 si cu diferenta dintre oricare doi termeni aflati pe pozitii
consecutive cel mult 2, obtinandu-se solutiile (1, 2, 3,4), (1, 2, 4), (1, 3, 4), (2, 3, 4), (2, 4). Folosind aceeasi
metoda generam toate sirurile strict crescatoare de numere naturale nenule mai mic sau egale cu 6, avand
primul termen 1 sau 2, ultimul termen 6 si diferenta dintre oricare doi termeni aflati pe pozitii consecutive cel
mult 2, care dintre afirmatiile urmatoare este adevarata:
a. imediat dupa solutia (1, 3, 4, 5, 6) se genereaza solutia (2, 3, 4, 5, 6)
b. penultima solutie generata este (2, 3, 5, 6)
c. imediat dupa solutia (1, 2, 4, 6) se genereaza solutia (1, 3, 4, 6)
d. in total sunt generate 13 solutii.
suma cifrelor egala cu 2 astfel: 2, 11, 20, 101, 110, 200, etc. Folosind acest algoritm generati numerele cu
cifrele 0, 1 si 2 care au suma cifrelor egala cu 3. Care va fi al saptelea numar din aceasta generare?
a. 120
b. 1002
c. 201
d. 210
58 . Generarea tuturor cuvintelor de 4 litere, fiecare litera putand fi orice element din multimea
cifrelor egala cu un numar natural s introdus de la tastatura, unde s si k sunt numere naturale nenule. Astfel
pentru valorile k = 2 si s = 6 se genereaza numerele: 15, 24, 33, 42, 51, 60. Care vor fi primele 4 numere ce
se vor genera pentru k = 3 si s=8?
a. 800, 710, 620, 530 c. 125, 233, 341, 431
b. 107, 116, 125, 134 d. 116, 125, 134, 143
cartezian AxBxC se genereaza, in ordine astfel: (1, 1, 2), (1, 1, 3), (1, 1, 4), (2, 1, 2), (2, 1, 3), (2, 1, 4), (3, 1,
2), (3, 1, 3), (3, 1, 4). Daca prin acelasi algoritm se genereaza produsul cartezian al multimilor AxBxC, unde
A = {a}, B ={a, b}, C = {b, c, d}, atunci cel de-al patrulea element generat este:
a. (a, b, c) c. (a, b, b)
b. (a, c, b) d. (a, c, d)
nenule distincte (abstractie facand de ordinea termenilor) se foloseste metoda backtracking obtinandu-se, in
ordine, toate solutiile 1+2+5, 1+3+4, 1+7, 2+6, 3+5. Aplicand exact acelasi procedeu, se determina solutiile
pentru scrierea numarului 10. Cate solutii de forma 1+ ... exista?
a. 3 c. 5
b. 4 d. 6
cartezian AxBxC se genereaza, folosind metoda backtracking, in ordinea (1, 1, 2), (1, 1, 3), (1, 1, 4), (2, 1,
2), (2, 1, 3), (2, 1, 4), (3, 1, 2), (3, 1, 3), (3, 1, 4). Daca prin acelasi algoritm se genereaza produsul cartezian
al multimilor AxBxC unde A = {x, y}, B = {x}, c = {x, y, z}, atunci cel de-al treilea element generat este:
a. (x, x, y) c. (x, x, z)
b. (x, y, x) d. (x, y, z)
63 . Generarea tuturor sirurilor formate din trei elemente, fiecare element putand fi oricare numar
din multimea {1, 2, 3}, se realizeaza cu ajutorul unui algoritm echivalent cu algoritmul de generare a:
a. permutarilor c. produsului cartezian
b. combinarilor d. aranjamentelor
64 . In utilizarea metodei backtracking pentru a genera toate cuvintele alcatuite din doua litere
ale multimii {a, c, e, q}, astfel incat sa nu existe doua consoane alaturate, cuvintele se genereaza in
urmatoarea ordine: aa, ac, ae, aq, ca, ce, ea, ec, ee, eq, qa, qe. Daca se utilizeaza exact aceeasi metoda pentru
a genera cuvinte formate din 4 litere ale multimii {a, b, c, d, e, f}, astfel incat sa nu existe doua consoane
alaturate in cuvant, care este penultimul cuvant generat?
a. fefa c. feef
b. fafe d. fefe
65 . Utilizand metoda backtracking se genereaza toate numerele formate doar din trei cifre astfel
incat fiecare numar sa aiba cifrele distincte. Cifrele fiecarui numar sunt din multimea {12, 2, 3, 4}. acest
algoritm genereaza numerele, in aceasta ordine: 123, 124, 132, 134, 213, 214, 231, 234, 312, 314, 321, 324,
412, b413, 421, 423, 431, 432. Daca utilizam acelasi algoritm pentru a genera toate numerele de 4 cifre,
fiecare numar fiind format din cifre distincte din multimea {1, 2, 3, 4, 5}, precizati care este numarul generat
imedia dupa 4325.
a. 4351 c. 4521
b. 5123 d. 4321
66 . Utilizand metoda backtracking se genereaza toate numerele palindrom formate din 4 cifre.
Fiecare numar contine cifre din multimea {1, 3, 5}. Elementele sunt generate in urmatoarea ordine: 111,
1331, 1551, 3113, 3333, 3553, 5115, 5335, 5555. Daca se utilizeaza exact aceeasi metoda pentru a genera
toate numerele palindrom formate din 4 cifre, fiecare element avand cifre din multimea {1, 2, 3, 4, 5, 6, 7, 8,
9}. Sa se precizeze cate numere pare se vor genera.
a. 99 c. 36
b. 40 d. 72
67 . Utilizand metoda backtracking se genereaza elementele produsului cartezian a n multimi A1,
A2, ..., An. Daca utilizam acest algoritm pentru a genera elementele produsului cartezian a 3 multimi: M = {1,
2, 3}, N = {1, 2} si P = {1, 2, 3, 4} atunci care din urmatoarele secvente nu reprezinta o solutie acestui
algoritm, pentru produsul cartezian PxNxM?
a. (4, 2, 3) c. (3, 2, 1)
b. (3, 3, 3) d. (1, 1, 1)
68 . Utilizand metoda backtracking se genereaza toate numerele de cate 3 cifre astfel incat
fiecare numar generat are cifrele distincte si suma lor este un numar par. Precizati care dintre urmatoarele
numere reprezinta o solutie a algoritmului?
a. 235 c. 281
b. 986 d. 455
aranjare a 8 dame pe tabla de sah astfel incat aceastea sa nu se atace. fiecare solutie se exprima sub forma
unui vector c = (c1, c2, ..., c8) unde c1 reprezinta coloana pe care se afla dama de pe linia i. Stiind ca primele
doua solutii generate sunt (1, 5, 8, 6, 3, 7, 2, 4), (1, 6, 8, 3, 7, 4, 2, 5) sa se determine solutia generata de
algoritm imediat dupa solutia (8, 2, 4, 1, 7, 5, 3, 6).
a. (8, 1, 2, 3, 4, 5, 6, 7) c. (8, 2, 5, 3, 1, 7, 4, 6)
b. (8, 4, 2, 7, 6, 1, 3, 5) d. (7, 4, 2, 5, 8, 1, 3, 6)
70 . Se genereaza toate sirurile strict crescatoare de numere naturale nenule mai mici sau egale cu
4, avand primul termen 1 sau 2, ultimul termen 4 si cu diferenta dintre oricare doi termeni aflati pe pozitii
consecutive cel mult 2, obtinandu-se solutiile (1, 2, 3, 4), (1, 2, 4), (1, 3, 4), (2, 3, 4), (2, 4). Folosind aceeasi
metoda, generam toate sirurile strict crescatoare de numere naturale nenule mai mici sau egale cu 5, care
dintre afirmatiile urmatoare este adevarata:
a. imediat dupa solutia (1, 3, 5) se genereaza solutia (2, 3, 4, 5).
b. imediat dupa solutia (2, 3, 5) se genereaza solutia (2, 5).
c. penultima solutie generata este (2, 4, 5).
d. in total sunt generate 5 solutii.
71 . Se genereaza in ordine crescatoare numerele de cate sase cifre care contin cifra 1 o singura
data, cifra 2 de cate doua ori si cifra 3 de trei ori. Se obtin, in aceasta ordine, numerele 122333, 123233,
123323, ...,333221. care din urmatoarele propozitii este adevarata?
a. Imediat dupa numarul 332312 se genereaza 332321
b. Sunt 8 numere generate prin aceasta metoda care au prima cifra 1 si ultima cifra 2.
c. Sunt 6 numere generate prin aceasta metoda care au prima cifra si a doua cifra 2.
d. Penultimul numar generat este 333122.
cuvantului caiet. Stiind ca primele 2 solutii sunt aceit si aceti, care este cuvantul generat inaintea cuvantului
tiaec?
a. teica c. ticae
b. tieac d. tiace
73 . O singura statie de servire (procesor, pompa de benzina etc) trebuie sa satisfaca cererile a n
clienti. Timpul de servire necesar fiecarui client este cunoscut in prealabil: pentru clientul i este necesar un
timp ti, 1 ≤ i ≤ n. Daca dorim sa minimizam timpul total de asteptare atunci
a. selectam intotdeauna clientul cu timpul maxim de servire din multimea de clienti ramasa
b. selectam intotdeauna clientul cu timpul minim de servire din multimea de clienti ramasa
75 . Managerul artistic al unui festival trebuie sa selecteze o multime cat mai ampla de spectacole
care pot fi jucate in singura sala pe care o are la dispozitie. Stiind ca i s-au propus 8 spectacole si pentru
fiecare spectacol i-a fost anuntat intervalul in care se va desfasura:
1: [10, 15)
2: [2, 4)
3: [7, 9)
4: [21, 25)
5: [10, 12)
6: [12, 15)
7: [7, 8)
8: [20, 27)
Care spectacole trebuie selectate pentru a permite spectatorilor sa vizioneze un numar cat mai mare de
spectacole?
a. 2, 3, 5, 6, 8
b. 1, 8
c. 2, 4, 5, 6, 7
d. 2, 3, 1, 8
greutatile 8kg, 6kg si 4kg. Pentru fiecare kg transportat castigul obtinut este 1 LEU.
Stiind ca obiectele se incarca integral in sac si ca se poate alege cel mult un obiect din fiecare tip, atunci
solutia optima este (se noteaza prin 1 - selectarea obiectului, iar prin 0 - neselectarea acestuia):
a. (1, 0, 0) c. (1, 1, 1)
b. (0, 1, 1) d. (1, 1, 0)
77 . Se doreste planificarea optimala (penalizarea totala sa fie minima) a 7 lucrari, fiecare lucrare
i fiind data prin termenul de predare t[i] si penalizarea p[i] care se plateste in cazul in care lucrarea nu este
finalizata la timp. Se presupune ca pentru executarea unei lucrari este necesara o unitate de timp si ca nu se
pot executa doua lucrari in acelasi timp.
Se considera datele de intrare:
i t[i] p[i]
1 4 50
2 3 40
3 2 60
4 3 20
5 4 70
6 2 10
7 1 130
Care este penalizarea totala minima ce se poate obtine?
a. 10 c. 20
b. 130 d. 70
78 . Fie tabloul unidimensional a in care elementele sunt, in ordine 1, 3, 5, 7, 10, 16, 21. Pentru a
verifica daca numarul x = 4 se afla printre elementele tabloului, se aplica metoda cautarii binare. Care este
succesiunea corecta de elemente cu care se compara x?
a. 1, 3, 5
b. 7, 5, 3
c. 7, 3, 5
d. 21, 16, 10, 7, 5, 3
80 . Pentru cautarea unei valori intre elementele unui tablou ordonat descrescator vom utiliza
81 .
i) 1, 4, 6, 8, 9
Fie secventele de numere:
ii) 8, 5, 4, 3, 2, 1
iii) 2, 3, 8, 5, 9
Algoritmul de cautare binara se poate aplica direct, fara alte prelucrari prealabile
a. numai secventei i) c. numai secventei ii)
b. numai secventei iii) d. atat secventei i) cat si secventei ii)
82 . Se considera metoda sortarii prin interclasare a n siruri de caractere in ordine lexicografica
crescatoare. Presupunand ca procesul de divizare se bazeaza pe metoda injumatatirii la fiecare pas, atunci
timpul cerut de algoritm este:
a. O(n) c. O(n log2n)
b. O(n2) d. O(n ln n)
83
a.
. Pentru rezolvarea problemei Turnurilor din Hanoi se poate utiliza:
84 .
a. k-1 comparatii
Se considera algoritmul cautarii binare si 2k-1≤ n ≤ 2k. In cazul unei cautari cu succes se fac
85 . Fie S(n) numarul de comparatii necesar sortarii a n siruri de caractere prin metoda insertiei
b. d.
86 . Se presupune ca n siruri de caractere sunt sortate prin metoda sortarii rapide (quicksort).
Notam prin T(n) numarul mediu de comparatii pentru ordonarea lexicografica crescatoare a celor n siruri.
Atunci T(n) =
a. O(n) c. O(n ln n)
b. O(n2) d. O(n log2n)
void * bsearch(const void *x, const void *s, size_t dim, size_t n, int (*f)(const void *, const void *));
Atunci:
a. f este functie de comparare definita de c. s este adresa elementului ce va fi cautat
utilizator
b. x este tabloul in care se cauta d. n este numarul de componente ale sirului
in care se face cautarea
88 . Se considera arborele binar a carui reprezentare standard (ST[i] - descendent stang, DR[i] -
descendent drept) este ST = (2, 3, 4, 0, 6, 0, 0, 0, 0) si DR = (8, 5, 0, 0, 7, 0, 0, 9, 0), unde prin 0 s-a notat
lipsa descendentului corespunzator. Atunci prin parcurgerea in inordine, nodurile arborelui sunt vizitate
astfel:
a. 1, 2, 3, 4, 5, 6, 7, 8, 9 c. 4, 3, 2, 6, 5, 7, 1, 8, 9
b. 1, 2, 8, 3, 5, 9, 4, 6, 7 d. 4, 3, 6, 7, 5, 2, 9, 8, 1
89 . Metoda Divide et impera, cu divizare binara, pentru rezolvarea unei probleme relativ la
obiectele O1, O2, ..., On, se poarte reprezenta sub forma unui arbore binar. Daca fiecare secventa Op, Op+1, ....,
Oq se reprezinta prin perechea (p, q), atunci varfurile terminale ale arborelui sunt etichetate cu:
a. (1, n)
b. (n+1, ∞)
c. (p, q) cu q = p+1
d. (p, q) cu q-p ≤ ε, unde ε este dimensiunea subproblemei ce se poate rezolva direct.
Metoda backtracking (modele de subiecte)
1. [Cuvinte]
Urmatorul enunt este comun pentru intrebarile i)- iv). “Utilizând metoda backtracking
se generează în ordine lexicografică cuvintele de câte patru litere din mulţimea
A={a,b,c,d,e}, cuvinte care nu conţin două vocale alăturate. Primele opt cuvinte
generate sunt, în ordine: abab, abac, abad, abba, abbb, abbc, abbd, abbe. “
vi) Se utilizează metoda backtracking pentru a genera toate cuvintele formate din
două litere distincte din muţimea {w,x,z,y} astfel încât niciun cuvânt să nu înceapă cu
litera x şi niciun cuvânt să nu conţină litera w lângă litera z. Cuvintele vor fi generate
în ordinea wx, wy, zx, zy, yw, yx, yz. Folosind aceeaşi metodă se generează toate
cuvintele de două litere distincte din mulţimea {w,x,z,y,t} astfel încât niciun cuvânt să
nu înceapă cu litera x şi niciun cuvânt să nu conţină litera w lângă litera z. Care este a
treia şi a patra soluţie generată?
2. [Combinari]
ii) Utilizând metoda backtracking sunt generate numerele de 3 cifre care au cifrele în
ordine crescătoare, iar cifrele aflate pe poziţii consecutive sunt de paritate diferită.
Ştiind că primele cinci soluţii generate sunt, în această ordine, 123, 125, 127, 129,
145, care este cel de al 8-lea număr generat?
a. 169 b. 149 c. 167 d. 147
iii) Utilizând metoda backtracking, sunt generate toate numerele de 3 cifre, astfel încât
cifrele sunt în ordine crescătoare, iar cifrele aflate pe poziţii consecutive sunt de
paritate diferită. Ştiind că primele trei soluţii generate sunt, în această ordine, 123,
125, 127, câte dintre toate numerele generate au suma cifrelor egală cu 6?
iv) Utilizând metoda backtracking se generează numerele formate din câte 3 cifre
distincte din mulţimea {1, 3, 5, 7}. Dacă primele trei numere generate sunt, în acestă
ordine: 135, 137, 153 care este cel de-al patrulea număr generat?
a. 157 b. 173 c. 315 d. 357
a) Dacă n este egal cu 5, câte numere au fost generate de catre program? __________
b) Pentru n egal cu 5, câte dintre numerele generate au prima cifră 4? ___________
xi) Se generează în ordine crescătoare toate numerele de exact 4 cifre care se pot
forma cu elementele mulţimii {0, 1, 2, 3, 4}. Primele 8 soluţii generate sunt, în ordine:
1000, 1001, 1002, 1003, 1004, 1010, 1011, 1012. Care sunt primele trei numere ce se
vor genera imediat după numărul 3443?
a. 4000, 4001, 4002
b. 3444, 4443, 4444
c. 3444, 4444, 4000
d. 3444, 4000, 4001
5. [Siruri de biti]
ii) Un algoritm generează, în ordine lexicografică, toate şirurile alcătuite din câte n
cifre binare (0 şi 1). Ştiind că pentru n=5, primele 4 soluţii generate sunt 00000,
00001, 00010, 00011, precizaţi care sunt ultimele 3 soluţii generate, în ordinea
obţinerii lor. _____________________
ii) Folosind un algoritm de generare putem obţine numere naturale de k cifre care au
suma cifrelor egală cu un număr natural s. Astfel, pentru valorile k=2 şi s=6 se
generează, în ordine, numerele: 15, 24, 33, 42, 51, 60. Care va fi al treilea număr
generat pentru k=4 şi s=5?
a. 1301 b. 1022 c. 2201 d. 1031
vii) Utilizând metoda backtracking, se generează numerele naturale formate din exact
3 cifre şi care au suma cifrelor egală cu 4, în această ordine: 103, 112, 121, 130, 202,
211, 220, 301, 310, 400. Dacă utilizăm acelaşi algoritm pentru a genera toate
numerele de 4 cifre care au suma cifrelor egală cu 7, precizaţi care este numărul
generat imediat după 1222.
a. 1231 b. 1223 c. 1213 d. 1321
7. [Permutari]
ii) Generarea tuturor cuvintelor de trei litere mici, nu neapărat distincte, ale alfabetului
englez, se poate realiza cu ajutorul unui algoritm echivalent cu cel de generare a:
a. produsului cartezian
b. combinărilor
c. aranjamentelor
d. permutărilor
iii) Pentru generarea tuturor mulţimilor de câte 5 cifre, având la dispoziţie cifrele de la
1 la 9, se poate utilza un algoritm echivalent cu algoritmul de generare a:
a. permutărilor de 5 elemente
b. submulţimilor mulţimii {1,2,3,4,5,6,7,8,9}
c. combinărilor de 9 elemente luate câte 5
d. aranjamentelor de 9 elemente luate câte 5
iv) Pentru a genera toate numerele naturale cu exact 4 cifre şi care au cifrele în ordine
strict descrescătoare, se poate utiliza un algoritm echivalent cu cel pentru generarea:
a. aranjamentelor de 4 obiecte luate câte 10
b. combinărilor de 10 obiecte luate câte 4
c. permutărilor a 10 obiecte
d. permutărilor a 4 obiecte
vi) Pentru rezolvarea cărei probleme dintre cele enumerate mai jos se poate utiliza
metoda backtracking ?
a. determinarea reuniunii a 3 mulţimi
b. determinarea tuturor divizorilor unui număr din 3 cifre
c. determinarea tuturor elementelor mai mici decât 30000 din şirul lui Fibonacci
d. având 3 culori (”roşu”, ”galben”, ”albastru”), determinarea tuturor variantelor în
care se pot genera toate steagurile cu 3 culori având la mijloc culoarea ”galben”
vii) La un concurs sportiv sunt 5 echipe, iar în fiecare echipă sunt câte 10 elevi.
Problema determinării tuturor grupelor de câte 5 elevi, câte unul din fiecare echipă,
este similară cu generarea tuturor:
a. elementelor produsului cartezian AxAxAxAxA, unde A={1,2,…,10}
b. submulţimilor cu 5 elemente ale mulţimii {1,2,…,10}
c. permutărilor mulţimii {1,2,3,4,5}
d. partiţiilor mulţimii {1,2,…,10}
viii) Problema generării tuturor codurilor formate din exact 4 cifre nenule, cu toate
cifrele distincte două câte două, este similară cu generarea tuturor:
a. aranjamentelor de 9 elemente luate câte 4
b. permutărilor elementelor unei mulţimi cu 4 elemente
c. elementelor produsului cartezian AxAxAxA unde A este o mulţime cu 9 elemente
d. submulţimilor cu 4 elemente ale mulţimii {1,2,3,4,5,6,7,8,9}
9. [Siruri de caractere]
ii) Utilizând metoda backtracking se generează toate cuvintele de câte 3 litere din
mulţimea {a,b,c}. Dacă primele patru cuvinte generate sunt, în acestă ordine: aaa, aab,
aac, aba, care este cel de-al optulea cuvânt generat?
a. acb b. acc c. aca d. bca
iii) Se utilizează metoda backtracking pentru a genera toate cuvintele de câte patru
litere distincte din mulţimea {d,a,n,s}. Ştiind că al doilea cuvânt generat este dans, iar
al treilea este dsan, care va fi ultimul cuvânt obţinut?
a. nsad b. snad c. snda d. dans
iv) Se utilizează metoda backtracking pentru a genera toate cuvintele de câte trei litere
distincte din mulţimea {i,n,f,o}. Ştiind că ultimele trei cuvinte generate sunt, în
ordine, ion, inf şi ino, care este cel de-al doilea cuvânt obţinut?
a. ofn b. ifo c. foi d. nif
v) Se utilizează metoda backtracking pentru a genera toate cuvintele care conţin toate
literele din mulţimea {i,n,f,o}, astfel încât fiecare literă să apară exact o dat într-un
cuvânt. Ştiind că al doilea cuvânt generat este info iar al treilea este ionf, care este
ultimul cuvânt obţinut?
a. nifo b. ofni c. ofin d. foni
vi) Se utilizează metoda backtracking pentru a genera toate cuvintele care conţin toate
literele din mulţimea {i,n,f,o}, astfel încât fiecare literă să apară exact o dat într-un
cuvânt şi literele n şi o să nu se afle pe poziţii vecine. Ştiind că primul cuvânt generat
este info, iar al treilea este nifo care este cel de-al doilea cuvânt obţinut?
a. iofn b. inof c. ionf d. niof
10 [Numarare …]
i) Câte numere cu exact 3 cifre pot fi construite folosind doar cifre pare?
a. 125 b. 100 c. 64 d. 128
vii) Prin metoda backtracking se generează toate anagramele (cuvintele obţinute prin
permutarea literelor) unui cuvânt dat. Ştiind că se aplică această metodă pentru
cuvântul pescar, precizaţi câte cuvinte se vor genera astfel încât prima şi ultima literă
din fiecare cuvânt generat să fie vocală (sunt considerate vocale caracterele a, e, i , o,
u)?
a. 96 b. 24 c. 48 d. 12
viii) În câte dintre permutările elementelor mulţimii {‘I’,’N’,’F’,’O’} vocala ‘I’ apare
pe prima poziţie?
a. 1 b. 24 c. 6 d. 12
iv) Completarea unui bilet de LOTO presupune colorarea a 6 numere dintre cele 49,
înscrise pe bilet. O situaţie statistică pe o anumită perioadă de timp arată că cele mai
frecvente numere care au fost extrase la LOTO sunt: 2, 20, 18, 38, 36, 42, 46, 48. Câte
bilete de 6 numere se pot completa folosind doar aceste valori, ştiind că numărul 42
va fi colorat pe fiecare bilet?
a. 21 b. 6! c. 42 d. 56
v) Se generează prin metoda backtracking mulţimile distincte ale căror elemente sunt
numere naturale nenule şi care au proprietatea că suma elementelor fiecărei mulţimi
este egală cu 7. Astfel, sunt generate, în această ordine, mulţimile: {1, 2, 4}, {1, 6},
{2, 5}, {3, 4}, {7}. Folosind aceeaşi metodă pentru a genera mulţimile distincte ale
căror elemente sunt numere naturale nenule şi care au proprietatea că suma
elementelor fiecărei mulţimi este egală cu 9, stabiliţi în ce ordine sunt generate
următoarele mulţimi: M1={2, 3, 4}; M2={3, 6}; M3={2, 7}; M4={4, 5}.
vi) Se generează în ordine strict crescătoare numerele de câte şase cifre care conţin:
cifra 1 o singură dată, cifra 2 de două ori şi cifra 3 de trei ori. Se obţin, în această
ordine, numerele: 122333, 123233, 123323, …, 333221. Câte numere generate prin
această metodă au prima cifră 1 şi ultima cifră 2? ________________
vii) Se generează în ordine strict crescătoare toate numerele de câte şase cifre care
conţin: cifra 1 o singură dată, cifra 2 de două ori şi cifra 3 de trei ori. Se obţin, în
această ordine, numerele: 122333, 123233, 123323, …, 333221. Ce număr se
generează imediat după 332312?
1000
0100
0010
0001
1000
0100
0001
0010
1000
0010
0100
0001
Care este penultima soluţie?
a.
0001
0010
1000
0100
b.
0100
1000
0010
0001
c.
0001
0100
0010
1000
d.
0010
1000
0100
0001
xii) Construim anagramele unui cuvânt c1c2c3c4 prin generarea în ordine lexicografică
a permutărilor indicilor literelor cuvântului şi obţinem c1c2c3c4 c1c2c4c3 c1c3c2c4 …
c4c3c1c2 c4c3c2c1. Pentru anagramele cuvântului rateu, după şirul raetu, raeut, raute
cuvintele imediat următoare sunt:
a. rauet şi rtaeu
b. rtaeu şi rtaue
c. rauet şi rtaue
d. rtaeu şi ratue
xiii) Trei baieti, Alin, Bogdan şi Ciprian, şi trei fete, Delia, Elena şi Felicia, trebuie să
formeze o echipă de 3 studenti, care să participe la un concurs de prezentare software.
Echipa trebuie să fie mixtă (adică să conţină cel puţin o fată şi cel puţin un băiat).
Ordinea copiilor în echipă este importantă deoarece aceasta va fi ordinea de intrare a
studentilor în concurs (de exemplu echipa Alin, Bogdan, Delia este diferită de echipa
Bogdan, Alin, Delia). Câte echipe se pot forma, astfel încât din ele să facă parte
simultan Alin şi Bogdan? _______________