Click here to load reader
Upload
gabi
View
48
Download
2
Tags:
Embed Size (px)
DESCRIPTION
a
Citation preview
Topic Algoritmi si structuri de date
Algoritmi clasici
Backtracking, Divide et Impera, Greedy, Metoda programarii dinamice
Tipuri de date Lista simplu inlantuita, lista dublu inlantuita, stiva, coada,
Sortari SelectionSort, BubbleSort, InsertionSort, ShellSort, Mergesort, Quicksort
Grafuri BFS, DFS
Arbori Arbori binari
Cautari Hash table
Operatie Frecventa Notatie
Declarare variabila N+2 ~N
Asignare N+2 ~N
<, > ½(N+1)(N+2) ~ ½ N^2
== ½ N(N-1) ~ ½ N^2
Accesare elemente array
N(N-1) ~ N^2
Incrementare ½ N(N-1) pana la N(N-1)
~ ½ N^2 pana la ~ N^2
Adancime-Stiva
https://www.youtube.com/watch?v=zLZhSSXAwxI
https://www.youtube.com/watch?v=6VF2Q0pgUFI
https://www.youtube.com/watch?v=gm8DUJJhmY4
Latime-Coada
1
Preordine Radacina Stanga Dreapta , Inordine Stanga Radacina Dreapta , Postordine Stanga Dreapta Radacina
2.Recursivitate. Divide-et-impera Recursivitate
Modalitatea de gasi solutia unei probleme de dimensiune mare impartind-o in probleme dedimensiuni mai mici, dar de aceeasi forma ca problema initiala Subproblemele dintr-o solutie recursiva au aceeasi structura ca problema initiala Recursivitatea permite rezolvarea unor probleme complexe, scriind programe simple si elegante
Un exemplu simplu de recursivitatevoid CollectContributions(int n) {if (n <= 100)colecteaza banii de la unsingur donatorelse{gaseste 10 voluntarifiecare voluntar strangen/10 dolari //CollectContributions(n/10) combina banii stransi de voluntari}}
Structura unei functii recursive. Paradigma recursivitatii._ if (testeaza cazul simplu) {_ Calculeaza o solutie simpla fara recursivitate_ } else {_ Imparte problema in subprobleme de aceeasi forma_ Rezolva fiecare problema apeland recursiv functiaaceasta_ Combina solutiile subproblemelor astfel incat sa obtiisolutia problemei initiale }
2
3
4
Leap of faith_ Strategia psihologica: presupunerea ca orice apel recursiv simplu va merge corect._ Intelegerea acestei strategii este esentiala pentru aplicatiile practice_ fact(4) = 4 * fact(3)_ fact(3) este mai simplu decat fact(4), deci, presupunem ca merge corect – leap of faith
Fibonacci_ Problema reproducerii iepurilor (1202 – Leonardo Fibonacci)_ Fiecare pereche de iepuri produce o noua pereche in fiecare luna10_ Iepurii devin mai fertili in a doua luna a vietii lor_ Iepurii batrani nu mor niciodata_ Daca o pereche de iepuri nou nascuti apare in Ianuarie, cate perechi de iepuri vor fi pana
la finele anului? Calcularea numerelor Fibonacci
5
6
7
8
Cautarea binara_ Cautarea intr-un array sau vector a unui elementparticular_ De exemplu, daca lucram cu un array de string-uri near fi foarte folositoare o functie de urmatoarea forma:1ar _ int FindStringInArray(string key, string array[], int n);_ Returneaza indexul elementului egal cu key (daca sunt mai multe elemente, orice index este ok)_ Returneaza -1 daca nu a gasit niciun element egal cu key_ Algoritmul de cautare liniara – nu avem informatii cu privire la ordinea elementelor in array, astfel verificam element cu element. Strategia consuma foarte mult timp, in cazul array-urilor foarte mari._ Daca string-urile sunt asezate in ordine19 alfabetica, folosim strategia cautarii binare.Impartim array-ul in doua, comparam key cu elementul din mijloc, dupa care verificam sirul din stanga sau dreapta, in functie de caz.
Recursivitate mutuala_ Daca o functie f apeleaza o functie g, care la randul ei apeleaza functia f, apelurile functiilor sunt considerate recursive.21_ Deoarece functiile f si g se apeleaza una pe alta, acest tip de recursivitate se numesterecursivitate mutuala._ Sa testam daca un numar este par sau impar.
9
_ Daca limitam cautarea la multimea numerelor naturale, atunci numerele pare si impare pot fi caracterizate astfel:_ Predecesorul unui numar par este un numar impar._ Un numar este par, daca nu este impar.22_ Numarul 0 este par prin definitie.
Sa gandim recursiv!_ Reductionism - un obiect poate fi inteles prin intelegerea partilor sale componente_ Holism – un obiect intreg este mai mare decat suma partilor sale componente (recursivitate)24_ Cand scrii un program recursiv trebuie sa ignore detaliile apelurilor recursive._ Cand programul recursiv nu merge, cauta in eroarea in implementare recursiva, nu in mecanismul recursiv!Checklist pentru gasirea erorii_ Incepe programul recursiv cu cazul simplu? (programul trebuie sa inceapa cu if)_ Ai rezolvat cazul simplu corect? (daca ai scris fact(0) = 0 si nu fact(0) = 1, tot programul va merge prost)_ Descompunerea recursiva simplifica problema? (ai grija sa nu scrii o bucla infinita)_ Apelurile recursive sunt subprobleme de aceeasi forma cu cea initiala?_ Cand unim solutiile subproblemelor formam raspunsul intreg al problemei initiale ?
10
3.BacktrackingObiective_ Intelegerea modalitatii de folosire a backtrackingului ca strategie de rezolvare a problemelor_ Recunoasterea problemelor ce pot fi rezolvate cu backtracking_ Intelegerea modului in care se aplica recursivitatea in backtracking_ Abilitatea de a implementa recursivitatea in probleme de backtracking
Problema labirintului:Regula mainii drepte_ Pune mana dreapta pe perete_ Atat timp cat nu ai iesit din labirint {_ Mergi tinand mana dreapta pe zid _ }
Abordare recursiva :
11
Codarea problemei labirintului_ Reprezentarea labirintului trebuie sa fie o structura de date ce ne permite:_ sa codam peretii_ sa retinem pozitia curenta_ sa ne indice daca un anumit loc este marcat_ sa putem determina daca am iesit din labirint sau nu
12
13
Problema colorarii hartilor_ Vrem coloram harta din imagine folosind backtracking_ Scopul este de a folosi doar 4 culori, astfel incat oricare doua tari vecine sa nu aiba aceeasi culoare_ Vom considera statele in ordine alfabetica si vom folosi cele patru culori in ordinea urmatoare: rosu, galben, verde si albastru
14
_ Incepem prin apelarea metodei de colorare pentru a colora Colorado_ Aceasta metoda incepe cu o bucla for in care iteram lista cu culori posibile (rosu, galben, verde, albastru)._ Intai se verifica daca se poate colora cu rosu Colorado_ Se poate deoarece niciun dintre vecini nu e colorat, deci Colorado primeste rosu_ Metoda se aplica apoi pentru Idaho (in ordine alfabetica)_ Ce culoare va primi?
_ Idaho va primi culoare rosie, deoarece niciunul dintre vecinii sai e colorat cu rosu_ Apoi metoda va apela Kansas_ Ce culoare va primi?
_ Kansas e colorat cu galben_ Metoda incearca mai intai rosu, dar nu poate deoarece este culoarea lui Colorado, apoiincearca urmatoarea culoare din lista, galben_ Montana este colorata cu galben
_ Rosu nu merge deoarece Idaho e colorat cu rosu_ Se continua apelul cu Nebraska_ Ce culoare va primi?_ Nebraska se coloreaza cu verde_ Rosu nu merge, deoarece Colorado e colorat cu rosu. Galben nu merge, deoarece Kansas e deja colorat cu galben. Verde merge, deoarece niciun vecin nu este colorat cu verde
15
_ Se continua apelul cu North Dakota_ Ce culoare va primi?
_ North Dakota este colorata cu rosu, deoareceniciun vecin nu este colorat cu rosu_ Se apeleaza South Dakota
_ Ce culoare va primi?
_ South Dakota este colorata cu albastru_ Se apeleaza Utah
_ Ce culoare va primi?_ Utah va fi colorat cu galben_ Urmatorul apel va fi Wyoming
_ Ce culoare va primi?
_ Nicio culoare nu merge!!!!_ Ce va face metoda in continuare??!?!?!_ Va face un pas inapoi intorcandu-se la pasul dinaintea acestui apel recursiv_ Nu mai coloreaza cu galben Utah, alegand alta culoare
_ Ce culoare va alege?
16
_ Utah va fi colorat cu verde_ Metoda incearca un nou apel pentru colorarea lui Wyoming_ Ce culoare va primi?
_ Nicio culoare nu merge!!_ Metoda face din nou backtracking.._ Ce culoare va primi Utah?_ Utah va fi colorat cu albastru
_ Urmeaza apelul recursiv pentru Wyoming_ Ce culoare va primi?
_ Nicio culoare nu merge!!!!_ Backtracking.. Utah a epuizat culorile.._ Backtracking..
17
_ Metoda apeleaza South Dakota_ Nu mai avem culori de incercat pentru South Dakota
_ Backtracking.._ Metoda apeleaza North Dakota_ Ce culoare va primi?
_ North Dakota este colorata cu verde_ Apelam South Dakota
_ South Dakota este colorata cu rosu_ Apelam Utah
_ Ce culoare va primi?
_ Utah este din nou colorat cu galben_ Apelam Wyoming din nou..
18
_ Va merge oare de data aceasta?
_ Da!! Wyoming este colorat cu albastru!
Codarea problemei colorarii hartii_ O matrice map[V][V] – unde V este numarul de tari_ map[V][V] - matricea de adiacenta (1 daca tarile sunt vecine, 0 altfel)_ Un integer m care reprezinta numarul de culori cu care se poate colora harta_ color[V] – vector cu culori asignate fiecarei tari
19
20
4.Greedy:Algoritmi Greedy _ Plata in monezi _ Programarea intervalelor de timp_ Problema rucsaculuiPlata in monezi_ Scop. Date fiind urmatoarele monezi 1, 5, 10, 25, 100, sa se gaseasca o metoda pentru a plati unui client o anumita suma, folosind un numar minim de monezi._ Ex. 34 $_ Algoritmul casierului. La fiecare iteratie se adauga moneda cu cea mai mare valoare, astfel incat sa nu se depaseasca valoarea totala. _ Ex. 2.89 $
21
Algoritmul casierului_ La fiecare iteratie, adauga cea moneda cu cea mai mare valoare, astfel incat sa nu se depaseasca suma totala
_ Este algoritmul casierului optim? Proprietatile solutiei optime_ Proprietate. Numarul de monezi cu valoare 1 <= 4_ Inlocuim 5 monezi de 1 cu una de 5_ Proprietate. Numarul de monezi de 5 <= 1_ Proprietate. Numarul de monezi de 25 <= 3_ Proprietate. Numarul de monezi de 5 + numarul de monezi de 10 <= 2_ Inlocuim 3 monezi de 10 si 0 monezi de 5 cu una de 25 si una de de 5_ Inlocuim 2 monezi de 10 si una de 5 cu una de 25
Analiza algoritmului casierului_ Consideram modalitatea optima de a schimba ck<=x<ck+1: greedy ia moneda k_ Presupunem ca orice varianta optima va lua tot moneda k_ Daca nu, are nevoie de monezi de tipul c1, c2,..., ck pentru a aduna suma x_ Tabelul urmator indica faptul ca nicio solutie optima poate sa realizeze acest lucru_ Problema se reduce la x-ck centime, care prin inductie se rezolva optim cualgoritmul casierului
Programarea intervalelor de timp
22
_ Task-ul j incepe la timpul sj si se termina la timpul fj_ Doua task-uri sunt compatibile daca nu se suprapun_ Scop: sa se gaseasca cea mai mare submultime de task-uri compatibile
Algoritm greedy_ Consideram task-urile intr-o ordine naturala_ Alegem fiecare task, astfel incat sa fie compatibil cutask-urile deja alese_ Consideram task-urile in ordine crescatoare in functie sjConsideram task-urile in ordine crescatoare _ in functie fj_ Consideram task-urile in ordine crescatoare in functie fjsj_ Pentru fiecare task j, numaram conflictele cj. Programam
in ordine crescatoare in functie de cjAlgoritmul Finish-time-first
Analiza algoritmului_ Sa presupunem ca algoritmul finish-time-first nu esteoptim_ Demonstratie (prin contradictie)_ Sa presupunem ca greedy nu este optim si sa vedem cese intampla_ Fie i1,i2,...,ik task-urile alease de greedy_ Fie j1,j2,...,jm task-urile dintr-o solutie optima cu i1=j1, i2=j2,..., ir=jr, pentru cea mai mare valoare posibila a lui
r
23
Partitionarea intervalelor_ Cursul j incepe la ora sj si se termina la ora fj._ Scop: sa se gaseasca numarul minim de sali pentru a programa toate cursurile, astfel incat sa nu se tina doua cursuri in aceeasi sala, la aceeasi ora._ Ex. Acest orar foloseste 4 sali pentru 10 cursuri
Ex. Acest orar foloseste 3 sali pentru 10 cursuri
Algoritm greedy_ Consideram cursurile intr-o ordine naturala
24
_ Punem fiecare curs intr-o sala libera (care?) sau alocam o noua sala, daca toate sunt ocupate_ Consideram cursurile in ordine crescatoare in functie sj Consideram cursurile in ordine crescatoare _ in functie fj_ Consideram cursurile in ordine crescatoare in functie fjsj_ Pentru fiecare curs j, numaram conflictele cj. Programam in ordine crescatoare in functie de cj
Algoritm start-time-first
15Algoritm start-time-first_ Algoritmul start-time-first poate fi implementat in O(nlogn)._ Stocam clasele intr-o coada de prioritati (cheia-timpul de terminare a ultimului curs)_ Pentru a determina daca un curs j este compatibil cu o sala, comparam sj cu cheia minima a salilor k din coada de prioritati_ Pentru a adauga cursul j in sala k, crestem valoarea cheii lui k cu fj_ Numarul total de operatii din coada de prioritati este de O(n)_ Sortarea in functie de timpul de start este de O(nlogn)_ Implementarea aceasta alege sala k al carei curs se termina cel mai devreme
Analiza algoritmului start-time-first_ Algoritmul start-time-first nu va pune doua cursuri in aceeasi sala, in acelasi timp_ Algoritmul start-time-first este optim_ Fie d numarul de sali pe care le aloca algoritmul_ Sala d este libera pentru vroiam sa o alocam cursului j, care este incompatibil cu restul salilor d-1_ Toate aceste d sali se elibereaza dupa timpul sj_ Deoarece am sortat cursurile in functie de timpul de start, toate aceste cursuri incep mai devreme de sj_ Deci, avem d cursuri care se suprapun la timpul sj+Ɛ_ Observatie -> toate orarele folosesc mai mult de d Sali
Problema rucsacului_ Un hot intra intr-un magazin si vede urmatoarele obiecte
25
_ Rucsacul sau are capacitatea de 4 kg. Ce trebuie sa ia astfel incat sa-si maximizeze profitul?Problema rucsacului fractional_ Hotul poate sa ia o parte dintr-un obiect
Problema rucsacului 0-1_ Hotul poate sa ia obiectul doar intreg.
Solutia Greedy pentru problema rucsacului fractional_ Sortam obiectele descrescator in functie de cost/kg
26
_ Daca rucsacul are capacitate 5 kg atunci Solutia este:
_ O(nlogn)
_ Data fiind o multime de obiecte I
_ Fie P problema selectarii obiectelor din I, cu greutatea maxima K, astfel incat valoarea lor sa fie22
Maxima
_ Fie k limita curenta a greutatii. Initial k=K.
5.Metoda programarii DINAMICE:Programare dinamica_ O meta-tehnica (seamana cu divide-et-impera)_ Se foloseste atunci cand problema initiala se poatesparge in probleme asemanatoare, mai mici.2_ Se foloseste cand solutia se poate calcula recursivfolosind solutiile subproblemelor._ Algoritmul gaseste solutii la subprobleme si le
stocheaza in memorie pentru a le folosi mai tarziu.Conceptul de programare dinamica
27
_ Ideea de baza:_ Solutia optima a problemei consta in gasireasolutiilor optime ale subproblemelorSe rezolva de jos in sus, prin construirea unui tabel3_ al subproblemelor rezolvate, folosit pentru
rezolvarea problemei initiale.Problema rucsacului (recapitulare)_ Data fiind o multime de obiecte, sa se aleaga aceleacare maximizeaza valoarea totala si incap intr-unrucsac. Fiecare obiect are o greutate si o valoare. Nuputem cara mai mult de o anumita greutate W.4_ Obiect # Greutate Valoare 1 1 8 2 3 6 3 5 5
Problema rucsacului_ Exista doua versiuni ale acesteu probleme:_ 0-1_ Fractionala5_ 0-1: obiectele nu se pot fractiona; se rezolva cu metoda programarii dinamice_ Fractionala: obiectele se pot fractiona; se rezolva cu algoritmul greedy.Problema rucsacului 0-1_ Fie un rucsac cu o capacitate W si o multime S ce consta in n obiecte._ Fiecare obiect i are o greutate wi si o valoare bi (wi, bi si W sunt intregi)_ Problema: ce obiecte trebuie alese, astfel incat samaximizam costul?
28
Abordare brute-force_ Sa rezolvam mai intai problema folosind un algoritm direct_ Deoarece sunt n obiecte, inseamna ca sunt
_ Exista o metoda mai buna?_ Da, folosind un algoritm bazat pe programarea dinamica_ Putem identifica foarte simplu subproblemele Daca problema initiala are obiectele 1...n, atunci10_ o subproblema ar fi gasirea unei solutii optime pentru Sk = {obiecte etichetate 1...k}
Definirea unei subprobleme
29
_ Daca problema initiala are obiectele 1...n, atunci o subproblema ar fi gasirea unei solutii optime pentru Sk = {obiecte etichetate 1...k}11_ Este o definitie rezonabila pentru o subproblema_ Intrebarea este: putem descrie solutia finala Sn folosind subprobleme Sk?_ Din pacate, nu.Definirea unei subprobleme_ Deci, definitia unei subprobleme este gresita._ Sa adaugam un nou parametru: w, care va reprezenta greutatea exacta pentru fiecare submultime de obiecte_ Problema va trebui sa calculeze B[k,w]
Formula recursiva pentru subprobleme_ Formula recursiva pentru subprobleme
_ Inseamna ca cea mai buna submultime Sk care are greutatea totala w este_ Cea mai buna submultime Sk-1 care are greutatea w_ Cea mai buna submultime Sk-1 care are greutatea w-wk
plus obiectul k
_ Cea mai buna submultime Sk care are greutatea totala w, fie contine obiectul k, fie nu_ Primul caz: wk > w, obiectul k nu poate fi in parte a solutiei deoarece am depasi greutatea w_ Al doilea caz: wk <= k, obiectul k poate fi parte a solutiei, si vom alege solutia care are o valoarea mai mare
Algoritm Rucsac 0-1
30
Exemplu_ Sa rulam algoritmul pe urmatoarele date:_ n = 4 # obiecte_ W = 5 (greutate maxima)17_ Obiecte (greutate, castig)
_ (2,3), (3,4), (4,5), (5,6)
31
32
Cum gasim efectiv obiectele corecte?_ Toate informatiile de care avem nevoie se gasesc in tabel._ B[n,W] sunt valorile maxime ce pot fi introduse in rucsac_ Fie i = n si k=W_ If B[i,k]!=B[i-1,k]_ Marcam obiectul i ca fiind in rucsac_ i = i-1, k = k-wi_ Else_ i= i-1
33
6.Liste inlantuite
Liste simplu inlatuite_ O lista inlantuita este reprezentata printr-o serie de noduri conectate intre ele, unde fiecare nod este reprezentat de o structura de date.2_ O lista inlantuita poate sa-si modifice dimensiunea in timpul rularii programului._ Inserarea si stergerea de noduri se face mai rapid cu liste inlantuite decat cu vectori.Liste simplu inlatuite_ Fiecare nod dintr-o lista inlantuita contine informatii despre date._ Fiecare nod dintr-o lista inlantuita contine si un pointer care face legatura cu un alt nod.
Liste simplu inlatuite_ O lista simplu inlantuita se numeste “inlantuita” deoarece fiecare nod din ea are un pointer prin care se face legatura cu urmatorul nod din lista.
Cum se declara?_ In primul rand, trebuie sa declaram o structura de date pentru noduri. De exemplu, urmatoarea structura poate fi folosita pentru a crea o lista in care nodurile stocheaza date de tip float.5struct ListNode{float value;struct ListNode *next;
};_ Urmatorul pas este sa declaram un pointer care sa fie capul listei.• Odata declarata structura nod si creat capulListNode *head;
34
6listei ca pointer NULL, avem o lista simplu inlantuita vida.• Urmatorul pas il reprezinta implementarea operatiilor listei.Operatii cu liste_ Vom folosi declararea clasei din slide-ul urmator, care este stocata in FloatList.h.
Adaugarea unui nod la o lista_ A adauga un nod la o lista inlatuita inseamna a-l adauga la finalul listei._ Pseudocodul pentru aceasta operatie este prezentat mai jos. Codul C++ urmeaza.Creeaza un nou nod9Stocheaza date in noul nodDaca nu exista niciun nod in listaNodul este capul listeiAltfelParcurge lista pentru a gasi ultimul nodAdauga nodul la finalul listei
35
Program:
Programul pas cu pas_ Pointerul head este declarat ca variabila globala. head este automat initializat cu 0 (NULL), ceea ce indica faptul ca lista este vida._ Primul apel al appendNode trimite 2.5 ca argument.12In urmtoarele instructiuni, un nou nod este alocat inmemorie, 2.5 este copiat in membrul value iar NULL este atribuit pointerului next.newNode = new ListNode;newNode->value = num;
newNode->next = nULL;
36
_ Urmatoarea instructiune este if.if (!head)
head = newNode;
_ Nu mai exista instructiuni de executat, asa ca functia main preia controlul._ In cel de-al doilea apel al appendNode, 7.9 este argumentul. Inca o data, se creeaza un nou nod, se atribuie valoarea lui value si se asigneaza
NULL pointerului next.
_ Deoarece head nu mai pointeaza NULL, intram pe ramura de else.
_ nodePtr este deja la finalul listei, deci buclawhile se termina imediat. Ultima instructiunenodePtr->next = newNode; face canodePtr->next sa pointeze catre noul nod.
37
17Acest fapt insereaza newNode la finalul listei.
_ A treia oara cand metoda appendNode este apelata, 12.6 este argumentul. Inca o fata, primele 3 instructiuni creeaza un nou cu argumentul stocat ca valoare a lui value.
_ Apoi, else se executa. nodePtr pointeazacatre head.
_ Atat timp cat nodePtr->next nu este NULL, se executa while. Dupa prima iteratie, nodePtr va pointa catre al doilea nod din lista.
_ Testul din conditia lui while pica dupa prima iteratie deoarece nodePtr->next pointeaza acum catre NULL. Ultima instructiune, nodePtr ->next = newNode; face ca nodePtr->next sa pointeze catre noul nod. Asa se insereaza newNode la capatul listei.
38
Parcurgerea unei liste_ Functia displayList parcurge lista, afisand value a fiecarui nod. Urmatorul pseudocod reprezinta algoritmul. Codul C++ este pe22slide-ul urmator.Atribuie capul listei unui pointer nodAtat timp cat pointerul nod nu este NULLAfiseaza value a nodului la care pointeaza pointerul nod
Atribuie pointerul nod urmtorului nod al listei
Inserarea unui nod_ Folosind structura listNode, pseudocodul urmator prezinta un algoritm pentru gasireapozitiei corecte de inserare a unui nod nou.2_ Algoritmul presupune ca nodurile din lista sunt deja ordonate.Creeaza un nou nodStocheaza datele in noul nod
39
Daca nu sunt noduri in listaNoul nod va fi capul listeiAltfel26Gaseste primul nod a carei valoare este mai mare sau egala cu nouavaloare sau finalul listei. Insereaza noul nod inaintea celui gasit sau pe
ultima pozitie.
40
_ In insertNode, un nou nod este creat si argumentul functiei este copiat in value. Atat timp cat lista are deka noduri stocate in ea, ramura de else se va executa. Incepe prin a30asigna nodePtr lui head.
_ Atat timp cat nodePtr nu este NULL si nodePtr->value este mai mica decat num, bucla while va itera. Pe parcursul acestei iteratii previousNode va pointa catre acelasi nod ca si nodePtr. nodePtr va pointa mai apoi catre nodul urmator.
_ Inca o data, bucla testeaza conditia. DeoarecenodePtr nu este NULL si nodePtr->valueeste mai mica ca num, bucla itereaza a douaoara. In timpul celei de-a doua iteratii, atat
41
32previousNode cat si nodePtr avanseaza cu
un nod in lista.
Stergerea unui nod_ Un nod se sterge dintr-o lista inaltuita in doi pasi:_ Se scoate nodul din lista_ Se sterge nodul din memorie33
_ Functia deleteNode incepe in slide-ul urmator.
42
43
Variatii ale listelor inlantuite_ Lista dublu inlantuita
_ Lista circulara inlantuita
7. Stive si cozi
Stive si cozi (Stack vs. Queue)_ Colectii de obiecte_ Operatii: inserare, stergere, iterare, verificare daca sunt vide_ Inserarea e la fel la ambele_ Dar stergerea?
44
_ Stiva: Last in first out – LIFO_ Coada: First in first out – FIFO
Stive_ O stiva permite accesul la un singur element:ultimul introdus in stiva._ Daca scoatem din stiva ultimul element, vom avea acces la penultimul element s.a.m.d._ Majoritatea microprocesoarelor folosesc o arhitectura bazata pe stive_ Adaugarea unui nou element intr-o stiva se numeste push._ Scoaterea unui element dintr-o stiva se numeste pop.
45
46
47
48
Exemple: Verificare paranteze_ c[d] // corect_ a{b[c]d}e // corect_ a{b(c]d}e // incorect ] != (_ a[b{c}d]e} // incorrect_ a{b(c) // incorrect
49
50
51
Coada. Coada de prioritati_ Enqueue - a introduce elemente in coada
_ Dequeue - a scoate elemente din coada
52
53
54
Coada de prioritati_ La fel ca o coada obisnuita, coada de prioritatiare doua capete_ Inserarea in coada de prioritati se face dupa26
valoarea unei chei ce determina prioritatea.
55
56
57
8.Sortari elementare
Ordonare_ Sortare a oricarui tip de data (atat timp cat ele se pot ordona)_ Ordonarea este o relatie binara care satisface urmatoarele
proprietati:
_ Exemple:_ Multimea numerelor naturale sau reale_ Ordinea cronologica a datelor
_ Ordinea alfabeticaSelection sort_ La iteratia i, gaseste indexul min a celui mai micelement ramas in lista
_ Interschimba pe a[i] cu a[min].
58
59
60
61
62
Insertion sort_ La iteratia i, interschimba a[i] cu valorile mai
mari decat ea din stanga sa.
63
Shell sort_ Spre deosebire de BubbleSort in care secompara doua elemente adiacente, in ShellSortse compara doua elemente ce se afla la odistanta d unul de celelalalt.17_ d este initial egal cu jumatatea lungimii array-ului,
dupa care se injumatateste continuu.
64
9.Merge Sort
MergeSort_ Pasi._ Impartim array-ul in doua jumatati_ Sortam recursiv fiecare jumatate2
_ Combinam jumatatile
Demo_ Scop. Fiind date doua subarray-uri sortate a[lo]pana la a[mid] si a[mid+1] pana la a[hi], sa se
inlocuiasca cu array-ul sortat a[lo] a[hi].
65
66
67
68
69
70
10. Quick SortQuickSort_ Ocupa un loc in Top 10 cei mai buni algoritmi ai
secolului 20QuickSort_ Pasi._ Se amesteca elementele din array_ Se imparte array-ul astfel incat pentru un anumit j_ Pentru un element a[j]_ Nu exista niciun element mai mare ca el la stanga_ Nu exista niciun element mai mic ca el la dreapta4
_ Se sorteaza recursiv fiecare subarray
71
Demo_ Repeta pana cand indicii i si j se intersecteaza_ Parcurge cu i de la stanga la dreapta atata timp cat a[i] < a[lo]._ Parcurge cu j de la dreapta la stanga atata timp cat a[j] > a[lo].
_ Interschimba a[i] cu a[j].
QuickSort – detalii de implementare_ Folosirea inca unui array simplifica modalitatea deimplementare, dar creste costurile._ Testarea incrucisarii pointerilor i si j este mai complicatadecat pare.
72
10_ Cand exista duplicate, mai bine se opreste scanarea._ Amestecarea elementelor este necesara pentru garantiaperformantei._ Trebuie sa se aleaga aleator elementul de partitionare in
fiecare subarray.
73
74
Algoritmul QuickSort
75
76
77
78
11. Grafuri_ Intrebare: Cum reuseste Google sa gaseasca
lucruri?Cautare pe Web_ Toate navigarile pe Internet sunt de fapt cereripentru anumite pagini
79
_ Dar ce se intampla cand nu stim ce sa cautam?4_ Un “motor de cautare” este un server Web care
raspunde la cererile particulare de paginilor Web.Grafuri_ In Informatica si matematica aceasta structura senumeste graf._ Nodurile: paginile Web5
_ Muchiile: link-urile dintre paginiGrafuri_ Un graf este o structura formala de a reprezenta relatiiledintre obiecte._ Un graf G este reprezentat ca G = (V, E)._ V – multimea varfurilor6_ E – multimea muchiilor_ Operatiile pe grafuri includ:_ Parcurgere_ Cautarea
_ Verificarea daca exista muchie intre doua varfuri etc.
Exemple de grafuri_ Grafuri web_ Varfurile sunt paginile web_ Muchia de la u la v este link-ul catre v care apare in pagina u_ Program7_ Varfurile sunt functiile_ Muchiile sunt apelurile de functii_ Facebook
_ TwitterReprezentarea grafurilor1. Matricea de adiacenta_ O matrice |V| x |V|, unde elementul (u,v) = 1,
daca si numai daca exista muchie intre u si v.
80
Reprezentarea grafurilor2. Liste de adiacenta_ O lista cu |V| elemente, in care fiecare elementstocheaza cate o lista inlantuita a tuturor varfurilor
adiacente
Terminologie_ In grafurile orientate muchiile au o anumita directie si se numesc arce._ In grafurile neorientate muchiile au dublu sens.10_ Varfurile u si v sunt adiacente daca exista muchia (u,v)._ Un graf complet are oricare doua varfuri sunt unite printr-o muchie.
Graf de cost_ Fiecare muchie are asociat un cost.
Drum si ciclu
81
Arbori ca si grafuri_ Fiecare arbore este un graf cu anumite restrictii._ Arborele este orientat_ Nu exista cicluri13_ Exista un drum direct de la radacina pana la fiecare
nod.
82
Algoritm general de cautare
83
Cautarea in latime_ Nodul radacina este expandat intai, apoi toate celelalte noduri suntexpandate, apoi toti succesorii lor s.a.m.d._ Sunt considerate toate drumurile de lungime 1, apoi toate
drumurile de lungime 2 etc.
_ Daca exista o solutie, algoritmul garanteaza ca o va gasi, iar dacaexista mai multe solutii, algoritmul va gasi intai starea tinta aflata la
cel mai mic numar de noduri.
Algoritm cautare in latime
84
Cautarea in adancime_ Se expandeaza nodul radacina, apoi se merge pe un drum pana seajunge la cel mai adanc nivel al arborelui._ Numai cand se ajunge la final (la nodurile frunza), cautarea se intoarce
si expandeaza noduri de la nivele mai putin adanci.
Parcurgerea in adancime: A, B, D, H, I, E, J, K, C, F, L, M, G, N, O.Algoritm cautarea in adancime
85
Deci, cum reuseste Google?_ Web Crawl: se downloadeaza pagini cunoscute, secolecteaza link-uri catre alte pagini, se repetaprocesul_ Indexare: se construieste un index gigant care53asociaza fiecare cuvant cu o lista de pagini in careapare acel cuvant_ Cautare distribuita: se folosesc foarte multe
calculatoare pentru a cauta mai rapidUn tip special de graf: Arborele
86
12. Arbori
_ Scopul: rezolvarea cautarii intr-o baza de date._ Arbore.2_ Folositor_ Versatil
_ Recursiv in mod natural.Cautarea intr-o baza de date_ Inregistrari:_ Nume si Social Security Number (SSN)_ Operatii:_ Inserare student3_ Stergere student_ Cautare student dupa nume sau SSN_ Scop:
_ Cautare rapida intr-o baza de date mare
Alte aplicatii_ Agenda telefonica online_ Spell checker care cauta cuvintele in dictionar_ Server care cauta adrese IP4_ Compilator care cauta dupa nume de variabile
pentru a le vedea tipul si adresa de memorie
Reprezentarea datelor_ Definim Item.h pentru o inregistrare din baza de
Date
87
_ Cream ST.h pentru a defini operatiile.
Array nesortat pentru reprezentareabazei de date
_ Cautare secventiala
Array sortat pentru reprezentareabazei de date
_ Cautarea binara dupa cheie
88
89
Arbore binar de cautare (BTS)
_ Se mentine ordonarea si in subarbori!
13
90
Cautarea in arborele binar decautare_ Incepem de la nodul radacina_ Daca cheia nodului curent este k, returnam nod_ Mergem la stanga daca <k15
_ Mergem la dreapta daca >kCautarea in BTS
Inserarea in BTS_ Cautam dupa cheie in arbore_ Cautarea se termina la pointerul NULL_ Alocam memorie pt noul element si facem legatura cu arborele
91
92
Traversarea arborilor
13. Hash Table
Inregistrari si chei_ Sa presupunem ca avem o clasa Record care contineinformatii despre studentii de la academia Jedi.2_ Vrem sa stocam aceste date dupa o cheie predefinita_ Cheia poate fi numele, ID, GPA, sau oricare alta data._ Restul datelor sunt date satelit
_ Sa luam un prim exemplu unde cheia este Class Rank.
93
Inregistrari si chei_ Deci, atunci cand scriem o lista de intregi de fapt ne referim la o lista de inregistrari ale
unor studenti. _ Vrem sa stocam datele astfel incat sa le putem gasi rapid intr-o cautare.Indexarea prin cheie_ Sa presupunem ca stim dinainte ca sunt mai putin de 500de studenti la Academia Jedi._ Sa cream un vector de marime 500._ Sa punem studentul cu cheia i in locul v[i]. Deci indexul =4
Cheie
_ Mai multe inregistrari sunt libere, deci folosim prea multamemorie.
_ Dar cautarea unei chei este rapida. O(1)Hash Table_ Un hash table (o harta) este o lista de inregistrari in carecheia unei inregistrari este mapata catre un index din lista._ Legatura dintre index si cheie se numeste functie hash._ Cheile nu trebuie sa fie numere intregi.5_ Fiecare bloc din hash table se numeste bucket._ Hash table-ul mananca multa memorie._ Cautarea/stergerea/inserarea se face in O(1)._ Regula de aur in Informatica: daca vrei sa faci ceva care
sa mearga repede, iti trebuie multa memorie.
Coliziuni_ In exemplul nostru s-a presupus ca nu avem duplicate._ Adica, fiecare inregistrare din baza de date are cheie unica._ Totusi, aceasta presupunere nu este in general valabila._ In cazul nostru, doi studenti cu aceeasi GPA ar avea acelasiClass rank. Deci, ar fi mapati in acelasi loc in hash table.6_ O coliziune apare cand doua inregistrari sunt mapate cu acelasi
94
index._ Cea mai grea partea a programarii hash table-urilor este evitarea
coliziunilor.
Open Addressing_ Open addressing: mapeaza fiecare cheie cu un index, iar dacaacesta este deja luat, il mapeaza in locul urmator liber._ Atunci cand facem cautarea si nu gasim inregistrarea cautam sila indexul urmator._ Ne oprim din cautare cand gasim inregistrarea sau cand dam de7un index gol._ Evident, aceasta rezolvare devine problematica atunci cand
datele se clusterizeaza intr-o anumita parte a hash tablelului.
Chaining_ O alta solutie ar fi sa lasam fiecare bucket sastocheze mai multe inregistrari._ Acest proces se numeste chaining.8_ Fiecare index ar fi o lista de inregistrari (vector,lista inlantuita, arbore etc.)_ Deci, am putea sa facem hash table-ul nostru un
vector de vector de inregistrari.
Chei mai complicate_ In exemplul nostru am organizat inregistrariledupa class rank._ Dar daca am vrea organizam inregistrarile dupa9ID? 399-423-821 cum l-am stoca?_ Sau daca am vrea sa le organizam dupa nume?
Cum mapam un string?Functii hash_ Functia hash H(x) mapeaza pe x intr-un index din tabel._ In primul exemplu H(x)=x: H(357)=357_ Functia hash trebuie sa poata mapa si H(“luke
95
skywalker”)=357 si chiar intregi mai mari precum ID,10H(002-345-285) = 357._ O functie hash trebuie sa minimizeze numarul de coliziuni_ Crearea unei functii hash bune este esentiala pentru
crearea unui hash table bun.Hashing strings_ Prezentam un exemplu de functie hash pentru stringuri. Nota bene: nueste o functie buna._ Fiecarui caracter din string-ul s ii va fi luat codul ASCII si insumat.e.g.(int)(‘L’) = 76._ Daca vrem ca rezultatul sa incapa intr-un hash table de marimea11HASH_SIZE, facem mod pe acea marime.int index = 0for (int i = 0; i < s.length(); i++)index += (int)s[i];index = index%HASH_SIZE;
_ Cu HASH_SIZE = 500, “Luke Skywalker” este mapat cu indexul 390.Hashing Strings12_ Cum este mai mare marimea hash tablelului, cu atataveam mai putine coliziuni._ Cu cat folosim mai multa memorie, cu atat hash tablelul
devine mai eficient.
Hashing Strings_ Inainte de a mapa un index, trebuie convertita cheia intr-uninteger._ Este de preferat un integer mai mare, pentru a nu mapa doar oparte a hash tablelului.
_ Pentru stringuri putem aduna codurile ASCII ale caracterelor.
_ Dar cu aceasta metoda, ordinea caracterelor nu conteaza, deci,H(“Yoda”) = H(“adoY”)_ O solutie ar fi sa ponderam caracterele. De exemplu, fixam oconstanta 1 < B < 2 si calculam:
Metoda diviziunii
96
_ Functia de hashing prezentata anterior este un exemplu al
metodei diviziunii: unde cheia x este convertita in integer iar M este o14constanta._ In general M este marimea hash tablelului_ Programatorii aleg de obicei o marimea hash tablelului un
numar mare prim, pentru a evita coliziunile.Metoda multiplicarii_ O metoda populara de hashing este metoda multiplicarii
unde 0 < A < 1 si M = HASH_SIZE sunt constante._ Cu alte cuvinte, multiplicam M cu A*x si apoi rotunjum.15_ Aceasta metoda de hashing a fost inventata de Donald Knuth._ Alegerea lui A depinde de date. Knuth recomanda_ Daca respectivele chei sunt uniform repartizate, alegerea lui A
minimizeaza coliziunile.
1. Cautarea binara.
2. Se citeste un numar real x. Sa se calculeze radical de ordinul 3 din x folosind un algoritm de tip Divide et impera.
3. Se citeste un vector cu n elemente numere naturale. Sa se determine elementul minim din vector folosind divide et impera.
4. Se citeste un vector cu n elemente numere naturale. Sa se calculeze suma elementelor vectorului folosind divide et impera.
5. Turnurile din Hanoi.
6. Se citeste un vector cu n elemente numere naturale. Sa se calculeze CMMDC al elementelor vectorului folosind divide et impera.
7. Sa se rezolve ecuatia x^3+x-1=0 pe intervalul [0,1] folosind metoda divide et impera.
8. Se citesc doua numere, n si x, n natural si x real pozitiv. Fara a folosi functia pow, extrageti cu 3 zecimale exacte radicalul de ordinul n din x.
9. Scrieti o functie minmax care sa determine elementul minim si elementul maxim dintr-un tablou cu elemente intregi folosind metoda divide et impera.
10.Folosind metoda divide et impera, scrieti o functie care sa determine daca un tablou cu elemente intregi este ordonat crescator.
11.Maximul din vector
12.QuickSort
13.Sortarea prin interscalare (MergeSort)
14.Se citesc 3 numere naturale S, n si e cu urmatoarele semnificatii: S este o suma de bani care trebuie platita folosind bancnote care au valori puterile lui e de la 1 la e la n. Se se afiseze modalitatea de plata folosind un numar minim de bancnote de tipurile precizate.
15.Problema comis-voiajorului
16.Fiind data o tabla de sah de dimensiunea nxn si un cal în coltul stânga sus al acesteia, se cere sa se deplaseze calul pe tabla astfel încât sa treaca o singura data prin fiecare patrat al tablei.
17.Problema rucsacului
18.Problema programarii spectacolelor
19.Se citeste un numar natural n>=4. Sa se afiseze toate permutarile multimii {1, 2, ... n} care au proprietatea ca diferenta absoluta a oricaror 2 elemente alaturate este cel putin egala cu 2.
97
Divide et impera
Greedyy
98
20.Sa se afiseze toate permutarile multimii {1,2,...,n} care au proprietatea ca pentru orice element x din permutare (exceptandu-l pe primul) exista un element generat anterior care sa aiba valoare cu unu mai mica sau mai mare ca x.
21.Se citeste un numar natural n si o permutare a multimii {1,2,...,n}. Sa se afiseze permutarile multimii {1,2,...,n} in care oricare doua elemente alaturate nu au fost alaturate in parmutarea citita. Ex. Pt n= 4 si permutarea 1 2 3 4 , o permutare care respecta regula este 2 4 1 3
22.Se citeste un numar natural n. Afisati permutarile multimii 1,2,3...n in care pana la jumatate elementele sunt in ordine descrescatoare, iar de la jumatate pana la final in ordine crescatoare.
23.Se citeste un numar natural n. Afisati permutarile multimii 1,2,3...n in care elementele pare sunt puncte fixe (se afla pe pozitie egale cu valoarea lor).
24.Sa se scrie un program care reconstituie urmatoarea adunare: CINCI+ DOI=SAPTE
25. Casierul Se citeste un numar natural n si apoi n numere naturale ordonate strict crescator reprezentand valorile a n bancnote. Se citeste apoi o suma de bani s si se cere sa se plateasca in toate modurile posibile suma s cu bancnote de valorile precizate folosind cel putin o bancnota de fiecare valoare data. Se presupune ca avem la dispozitie oricate bancnote de fiecare valoare.
26.Se citeste un numar natural n. Sa se afiseze toate modurile in care poate fi descompus ca produs de numere naturale diferite de 1 si n.
27.Sa se aranjeze in toate modurile n pisici si m caini astfel incat nicio pisica sa nu fie asezata intre 2 caini.
28.Se citeste un numar natural n<30. Sa se afiseze toate modalitatile de a-l calcula prin adunari sau scaderi ale numerelor 1,2, ...n. Fiecare numar de la 1 la n va aparea o singura data în descompunerea lui n. Daca acest lucru nu este posibil, se va afisa mesajul „Imposibil”.
29.Se citeste un numar natural n. Sa se afiseze toate modalitatile de a-l descompune ca suma de numere naturale consecutive. Daca acest lucru nu este posibil, se va afisa mesajul „Imposibil”.
30.Fie n>0, natural. Sa se scrie un program care sa afiseze toate partitiile unui numar natural n. Numim partitie a unui numar natural nenul n o multime de numere naturale nenule {p1, p2, …, pk} care îndeplinesc conditia p1+p2+ …+pk = n.
31.Se citeste de la tastatura un numar natural n par, n<30. Sa se genereze si sa se afiseze pe ecran toate combinatiile de n paranteze rotunde care se închid corect. De exemplu, pentru n=4 se obtin urmatoarele combinatii: ( ( ) ) si ( ) ( ) .
32.Sa se scrie un program care genereaza si scrie într-un fisier toate cuvintele formate din n vocale mici (n numar natural citit de la tastatura, n<10), ordonate alfabetic. De exemplu, pentru n=3 se vor scrie în fisier:
33.Scrieti un program care citeste de la tastatura un numar natural nenul n (n<=20) si construieste toate numerele formate din n cifre impare cu proprietatea ca oricare doua cifre alaturare dintr-un numar generat sunt consecutive în multimea cifrelor impare. Exemplu: Pentru n=4 se obtin numere de forma: 1313, 1353, 1357, .... 7979...
99
100
Casierul prob 25
#include <fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
int x[100], a[100], n,s;
void citire(){ fin>>n; for(int i=1;i<=n;i++) fin>>a[i]; fin>>s;}
void afis(){ for(int i=1;i<=n;i++) if(x[i]!=0) fout<<x[i]<<"*"<<a[i]<<" "; fout<<endl;}
void back(int k,int sp){ int i; for(i=0;i<=(s-sp)/a[k];i++) { x[k]=i; sp=sp+x[k]*a[k]; if(sp<=s && k<=n) if(k==n && sp==s) afis(); else if(k<n) back(k+1,sp); sp=sp-x[k]*a[k]; }}
int main(){ citire(); back(1,0); fin.close(); fout.close(); return 0;} 25
Problema 26
#include<iostream>using namespace std;int n, a[100],m,x[100];
void afis(int k){
for(int i=1;i<=k;i++) cout<<x[i]<<" "; cout<<endl;}
void back(int k, int p){
if(p==n) afis(k-1);else
for(int i=1;i<=m;i++)
{
x[k]=a[i];
if(p*x[k]<=n && x[k]>=x[k-1]) back(k+1,p*x[k]);
}}
int main(){
cin>>n;m=0;for(int i=2;i<=n/2;i+
+) if(n%i==0)
a[++m]=i;back(1,1);return 0;
} 26
26
Problema 27
#include<iostream>
using namespace std;
int x[100],pus[100],n,m,nr=0;
void Write(){ for(int i=1;i<=n+m;i++) if(x[i]==1) cout<<"P ";
else cout<<"C "; cout<<endl; nr++;}
int cond(int k){ int c=0,p=0,i; for(i=1;i<=k;i++) if(x[i]==0) c++; else p++; if(p>n || c>m) return 0; if(k>=3) if(x[k-2]==0 && x[k-1]==1 && x[k]==0) return 0; return 1;}
void Sub(int k){ for(int i=1;i>=0;i--) { x[k]=i; if(cond(k)) if(k==n+m) Write(); else Sub(k+1); } }int main(){ cin>>n>>m; Sub(1); cout<<nr; system("pause"); return 0;}
Problema 27
#include<iostream.h>
int x[10],n,ns;
void scriesol (){ int j; int s=0; ns++; for(j=1;j<=n;j++) if(x[j]==1) s=s+j; else s=s-j; if(s==n) { cout<<endl; for(j=1;j<=n;j++) if(x[j]==1) cout<<"+"<<j; else cout<<"-"<<j;}}void back(int k){int i; for(i=0;i<=1;i++) { x[k]=i; if (k==n) scriesol(); else back(k+1);}}void main(){ cin>>n; back(1); if (ns==0) cout<<"Imposibil";}
Problema 28
#include<iostream.h>int n, ns,sol[20];void afis(int l){ int i; ns++; for(i=1;i<=l;i++) cout<<sol[i]<<" "; cout<<endl;}void back(int i, int sp){ int j; if (sp==n && i>2) afis(i-1); else for(j=sol[i-1]+1;j<=n-sp;j++)
if (j==sol[i-1]+1 || i==1){ sol[i]=j;
back(i+1, sp+j);}}void main(){cin>>n; ns=0; back(1,0); if (ns==0) cout<<"Imposibil";}
101
#include<iostream.h>int n, ns,sol[20];
void afis(int l){ int i; ns++; cout<<"Solutia nr. "<< ns<<" : "; for(i=1;i<=l;i++) cout<<sol[i]<<" "; cout<<endl;}
void back(int i, int sp){ int j; if (sp==n) afis(i-1); else for(j=1;j<=n-sp;j++)
if (j>=sol[i-1]){
sol[i]=j;
back(i+1, sp+j);
}}
void main(){ cin>>n; ns=0; back(1,0); cout<<ns<<" solutii";} Nr30 problema
#include<iostream.h>
int x[10],n;
void scriesol(){ int j; cout<<endl; for(j=1;j<=n;j++) if(x[j]==1) cout<<")"; else cout<<"(";}int cond(int k){ int i,pi=0,pd=0; for(i=1;i<=k;i++) if(x[i]==0) pd++; else pi++; return pd<=n/2 && pi<=pd;}void back(int k){ int i; for(i=0;i<=1;i++) { x[k]=i; if (cond(k))
if (k==n) scriesol();
else back(k+1); }}
void main(){ cin>>n; back(1);}
Problema nr 31
#include<iostream.h>
int x[10],n;char v[]="aeiou";
void scriesol(){ int j; cout<<endl; for(j=1;j<=n;j++) cout<<v[x[j]];}
void back(int k){ int i; for(i=0;i<=4;i++) { x[k]=i; if (k==n) scriesol(); else back(k+1); }}
void main(){ cin>>n; back(1);}Problema nr 32
#include<iostream.h>
int x[10],n;
void scriesol(){ int j; cout<<endl; for(j=1;j<=n;j++) cout<<x[j];}int cond(int k){ if(k>1) if(x[k]-x[k-1]==2 || x[k-1]-x[k]==2) return 1;
else return 0; else return 1;
}void back(int k){ int i; for(i=1;i<=9;i=i+2) { x[k]=i; if (cond(k))
if (k==n) scriesol();
else back(k+1); }}
void main(){ cin>>n; back(1);}
Problema nr 33
102
Se citeste un numar natural n si o permutare a multimii {1,2,...,n}. Sa se afiseze permutarile multimii {1,2,...,n} in care oricare doua elemente alaturate nu au fost alaturate in parmutarea citita.
#include<iostream.h> int x[100],a[20][20],p[100],n; void citire() { cin>>n; for(int i=1;i<=n;i++) cin>>p[i]; for(i=2;i<=n;i++) {
a[p[i-1]][p[i]]=1;a[p[i]][p[i-1]]=1;
} }
void afis() { for(int i=1;i<=n;i++) cout<<x[i]<<" "; cout<<endl; }
int cond(int k) { for(int i=1;i<=k-1;i++) if(x[k]==x[i]) return 0;
if(k>1 && a[x[k-1]][x[k]]==1) return 0;
return 1; }
void back(int k) { for(int i=1;i<=n;i++) { x[k]=i;
if(cond(k)) if(k==n) afis();
else back(k+1); } }
void main() { citire(); back(1); }
Se citeste un numar natural n. Afisati permutarile multimii 1,2,3...n in care pana la jumatate elementele sunt in ordine descrescatoare, iar de la jumatate pana la final in ordine crescatoare.
#include <fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
int n, sol[20], p[20];
void afis(){ for(int i=1;i<=n;i++) fout<<sol[i]<<" "; fout<<endl;}
int valid(int k){ if(k>1) if(k<=(n+1)/2) { if(sol[k]>sol[k-1]) return 0; } else if(sol[k]<sol[k-1]) return 0; return 1;}
void back(int k){ for(int i=1;i<=n;i++) if(p[i]==0) { sol[k]=i; p[i]=1; if(valid(k)) if(k==n) afis(); else back(k+1); p[i]=0; }}
int main(){ fin>>n; back(1); fin.close(); fout.close();}
Se citeste un numar natural n. Afisati permutarile multimii 1,2,3...n in care elementele pare sunt puncte fixe (se afla pe pozitie egale cu valoarea lor).
#include <fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
int n, sol[40], p[40];
void afis(){ for(int i=1;i<=n;i++) if(i%2==0) fout<<i<<" "; else fout<<sol[i]<<" "; fout<<endl;}
void back(int k){ for(int i=1;i<=n;i=i+2) if(p[i]==0) { sol[k]=i; p[i]=1; if(n%2==0 && k==n-1 || n%2==1 && k==n) afis(); else back(k+2); p[i]=0; }}
int main(){ fin>>n; back(1); fin.close(); fout.close();}
Cinci+Doi=7
#include<iostream.h> int x[8]; void afis() { cout<<x[1]<<9<<x[2]<<x[1]<<9<<"+"<<endl; cout<<" "<<x[3]<<x[4]<<9<<"="<<endl; cout<<"------"<<endl; cout<<x[5]<<0<<x[6]<<x[7]<<8<<endl<<endl; } int cond(int k) { if(k==7) if(x[1]+x[4]+1!=x[7] && x[1]+x[4]+1!=x[7]+10 ) return 0; if(k>=6) { if(x[1]+x[4]+1<10)
if(x[2]+x[3]<10 || (x[2]+x[3])%10!=x[6]) return 0;
if(x[1]+x[4]+1>=10) if(x[2]+x[3]+1<10
|| (x[2]+x[3]+1)%10!=x[6]) return 0; } if(k>=5) if(x[1]+1!=x[5]) return 0; for(int i=1;i<k;i++)
if(k>=5) if(x[1]+1!=x[5]) return 0; for(int i=1;i<k;i++) if(x[i]==x[k]) return 0; return 1; }
void back(int k) { for(int i=1;i<=7;i++)
{x[k]=i; if(cond(k)) if(k==7)
afis(); else back(k+1); } }
void main() { back(1); }
103
Problema programarii spectacolelor Intr-o sala de spectacol trebuie planificate n spectacole intr-o zi. Pentru fiecare spectacol se cunosc ora de inceput si ora de terminare (numere intregi). Sa se planifice un numar maxim de spectacole astfel inct sa nu fie doua spectacole care sa se suprapuna.
#include<fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
struct spectacol{ int s,d;};
void citire(int &n, spectacol a[]){ fin>>n; for(int i=1;i<=n;i++) fin>>a[i].s>>a[i].d;}
void ordonare(int n, spectacol a[]){ int i,j; spectacol aux; for(i=1;i<n;i++) for(j=i+1;j<=n;j++) if(a[i].d>a[j].d) { aux=a[i]; a[i]=a[j]; a[j]=aux; }}
void afisare(int n, spectacol a[]){ for(int i=1;i<=n;i++) fout<<a[i].s<<","<<a[i].d<<" ";}
void greedy(int n, spectacol a[]){ spectacol s[100]; int i,k; k=1; s[1]=a[1]; for(i=2;i<=n;i++) if(s[k].d<a[i].s) s[++k]=a[i]; afisare(k,s);}
int main(){ int n; spectacol a[100]; citire(n,a); ordonare(n,a); greedy(n,a); fin.close(); fout.close();} greedy restaurant
Se citeste un numar natural n>=4. Sa se afiseze toate permutarile multimii {1, 2, ... n} care au proprietatea ca diferenta absoluta a oricaror 2 elemente alaturate este cel putin egala cu 2.
#include<iostream.h> int x[100],p[100],n; void afis() {for(int i=1;i<=n;i++) cout<<x[i]<<" "; cout<<endl; }
int cond(int k) { if(k>1) if(x[k]-x[k-1]==1 || x[k]-x[k-1]==-1) return 0; return 1; }
void back(int k) { for(int i=1;i<=n;i++) if(!p[i]) { x[k]=i;
p[i]=1;if(cond(k)) if(k==n) afis(); else back(k+1);p[i]=0;
} }
void main() { cin>>n; back(1); } backtracking
#include<iostream.h> int x[50],n; void afis() { int i; for(i=1;i<=n;i++) cout<<x[i]; cout<<endl;} int cond(int k) { int i; for(i=1;i<=k-1; i++) if(x[k]==x[i]) return 0; if(k>1)
{ for(i=1;i<=k-1;i++) if(x[k]-x[i]==1 || x[k]-
x[i]==-1) return 1; return 0;}return 1;}
void back(int k) {int i; for(i=1;i<=n;i++) {x[k]=i; if(cond(k)) if(k==n) afis();
else back(k+1); } } void main() { cin>>n; back(1); }Sa se afiseze toate permutarile multimii {1,2,...,n} care au proprietatea ca pentru orice element x din permutare (exceptandu-l pe primul) exista un element generat anterior care sa aiba valoare cu unu mai mica sau mai mare ca x. backtracking
104
Problema comis-voiajorului (varianta 1 greedy)
#include<fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
int x[100],pus[100],n,s;int a[100][100];
void citire(){ int i,j; fin>>n; for(i=1;i<=n;i++) for(j=1;j<=n;j++) fin>>a[i][j];}
void Write(){ for(int i=1;i<=n;i++) fout<<x[i]<<" "; fout<<endl<<s;}
void voiajor(int k){ int min=100000,imin; for(int i=1;i<=n;i++) if(!pus[i] && a[x[k-1]][i]<min && i!=x[k-1]) { min=a[x[k-1]][i]; imin=i; } x[k]=imin; pus[imin]=1; s=s+a[x[k-1]][imin]; if(k==n) Write(); else voiajor(k+1);}
int main(){ citire(); x[1]=1; pus[1]=1; voiajor(2); fin.close(); fout.close(); return 0; GREEDY}
Fiind data o tabla de sah de dimensiunea nxn si un cal în coltul stânga sus al acesteia, se cere sa se deplaseze calul pe tabla astfel încât sa treaca o singura data prin fiecare patrat al tablei.
#include<fstream>#include<iomanip>using namespace std;const int dx[8]={-1,1,2,2,1,-1,-2,-2};const int dy[8]={-2,-2,-1,1,2,2,1,-1};int a[201][201],n,gata;ifstream fin("cal.in");ofstream fout("cal.out");
void afis(){ int i,j; fout<<"n="<<n<<endl; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) fout<<setw(4)<<a[i][j]<<" "; fout<<endl; } fout<<endl; gata=1;}
int inside(int i,int j){ return i>=1 && i<=n && j>=1 && j<=n;}
int nm(int i, int j)//calculeaza in cate pozitii poate merge din i,j{ int inou,jnou,k,x=0; for(k=0;k<8;k++)
{ inou=i+dx[k]; jnou=j+dy[k]; if(inside(inou,jnou) && a[inou][jnou]==0) x++; }
return x;}
void calgreedy(int i, int j, int pas){ int k,v,min=9,inou,jnou,ii,jj; if(!gata) { a[i][j]=pas; if (pas==n*n) afis(); else for(k=0;k<8;k++)
{ inou=i+dx[k]; jnou=j+dy[k]; if (inside(inou,jnou) && a[inou][jnou]==0) { //cauta pozitia cel mai greu accesibila v=nm(inou,jnou); if(v<min) { min=v; ii=inou; jj=jnou;} } }
if(min!=9) calgreedy(ii,jj,pas+1); a[i][j]=0; }}
int main(){ fin>>n; calgreedy(1,1,1); fout.close(); return 0;} Greedy
105
Problema rucsacului (cazul continuu) GreedyO persoana are un rucsac cu care poate transporta o greutate maxima g. Persoana are la dispozitie n obiecte pentru care stie greutatea si castigul obtinut daca transporta obiectul. Fiecare obiect poate fi transportat integral sau taiat. Sa se precizeze ce obiecte alege persoana si in ce proportie le ia astfel incat castigul total sa fie maxim si sa nu se depaseasca greutatea maxima a rucsacului.
#include<fstream>#include<iomanip>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
struct obiect{ float g,c,r;//greutate, castig, raportul cat se ia din obiect};
void citire(float &g, int &n, obiect a[]){ fin>>g>>n; for(int i=1;i<=n;i++) { fin>>a[i].g>>a[i].c; a[i].r=0;//initial nu se foloseste obiectul }}
void ordonare(int n, obiect a[])//ordonare dupa castig/greutate{ int i,j; obiect aux; for(i=1;i<n;i++) for(j=i+1;j<=n;j++) if(a[i].c/a[i].g<a[j].c/a[j].g) {aux=a[i]; a[i]=a[j]; a[j]=aux;} }
void afisare(int n, obiect a[]){ float c=0; for(int i=1;i<=n;i++) { fout<<a[i].g<<","<<a[i].c<<","<<setprecision(4)<<a[i].r<<"\n"; c=c+a[i].c*a[i].r; } fout<<"castig maxim="<<c;}
void greedy(float g, int n, obiect a[]){ obiect s[100]; int i,k; float sp=0; k=0; i=1; while(sp<g) { if(sp+a[i].g<=g) { sp=sp+a[i].g; s[++k]=a[i]; s[k].r=1;//obiect intreg } else { s[++k]=a[i]; s[k].r=(g-sp)/a[i].g;//obiect fractionat sp=g; } i++; } afisare(k,s);}
int main(){ int n; obiect a[100]; float g; citire(g,n,a); ordonare(n,a); greedy(g,n,a); fin.close(); fout.close();}
106
Quicksort
#include <fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
int poz(int a[50000], int s, int d){ int i,j,di,dj,aux; i=s; j=d; di=0; dj=1; while(i<j) { if(a[i]>a[j]) { aux=a[i]; a[i]=a[j]; a[j]=aux; di=1-di; dj=1-dj; } i=i+di; j=j-dj; } return j;}
void QS(int a[50000], int s, int d){ int p; if(s<d) { p=poz(a,s,d); QS(a,s,p-1); QS(a,p+1,d); }}
void citire(int a[50000], int &n){ int i; fin>>n; for(i=1;i<=n;i++) fin>>a[i];}
void afis(int a[50000], int n){ int i; for(i=1;i<=n;i++) fout<<a[i]<<"\n";}
int main(){ int a[50000], n; citire(a,n); QS(a,1,n); afis(a,n); return 0;} QSort
Sortarea prin interclasare (MergeSort)
#include <fstream>using namespace std;ifstream fin("date.in");ofstream fout("date.out");
void inter(int a[50000], int s, int m, int d){ int i,j,k,c[50000]; i=s; j=m+1;k=1; while(i<=m && j<=d) if(a[i]<a[j]) c[k++]=a[i++]; else c[k++]=a[j++]; while(i<=m) c[k++]=a[i++]; while(j<=d) c[k++]=a[j++]; k=1; for(i=s;i<=d;i++) a[i]=c[k++];}
void msort(int a[50000], int s, int d){ int m; if(s<d) { m=(s+d)/2; msort(a,s,m); msort(a,m+1,d); inter(a,s,m,d); }}
void citire(int a[50000], int &n){ int i; fin>>n; for(i=1;i<=n;i++) fin>>a[i];}
void afis(int a[50000], int n){ int i; for(i=1;i<=n;i++) fout<<a[i]<<" ";}
int main(){ int a[50000], n; citire(a,n); msort(a,1,n); afis(a,n); return 0;} Merge Sort
Se citesc 3 numere naturale S, n si e cu urmatoarele semnificatii: S este o suma de bani care trebuie platita folosind bancnote care au valori puterile lui e de la 1 la e la n. Se se afiseze modalitatea de plata folosind un numar minim de bancnote de tipurile precizate. Sa se afiseze la final numarul de bancnote folosite. Datele se vor citi din fisierul eur.in, iar rezultatele se vor afisa in fisierul eur.out.--------------------
#include <fstream>using namespace std;ifstream fin("eur.in");ofstream fout("eur.out");int main(){ int S,n,e,t=0; fin>>S>>n>>e; int p=1,k=0; while(p*e<=S && k<n )//calculez bancota maxima (<=S avand cel mult valoarea e la n){ p=p*e; k++; } while(S>0) { if(S>=p) fout<<S/p<<" bancnote de valoarea "<<p<<endl; //bancnotele de valoare p t=t+S/p;//numar bancnotele folosite S=S%p;//cat mai ramane de platit p=p/e;//bancnota urmatoare ca valoare (mai mica) }
107
Se citeste un vector cu n elemente numere naturale. Sa se calculeze CMMDC al elementelor vectorului folosind divide et impera. #include<iostream>
using namespace std;
int cmmdc(int a[100], int s, int d){ if(s==d) return a[s]; else { int x,y; x=cmmdc(a,s,(s+d)/2); y=cmmdc(a,(s+d)/2+1,d); while(x!=y) if(x>y) x=x-y; else y=y-x; return x; } }
int main(){ int a[100],n,i; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; cout<<cmmdc(a,1,n); system("pause"); return 0;}
Sa se rezolve ecuatia x^3+x-1=0 pe intervalul [0,1] folosind metoda divide et impera. #include<iostream>
using namespace std;
float f(float x){ return x*x*x+x-1;}
float DEI(float s, float d){ if(d-s<=0.0001) return s; else { float m=(s+d)/2; if(f(m)==0) return m; else if(f(m)<0) return DEI(m,d); else return DEI(s,m); }}
int main(){ cout<<DEI(0,1); system("pause"); return 0;}
Se citesc doua numere, n si x, n natural si x real pozitiv. Fara a folosi functia pow, extrageti cu 3 zecimale exacte radicalul de ordinul n din x. #include<iostream>#include<cmath>
using namespace std;
float f(float y, int n, float x){ float p=1; for(int i=1;i<=n;i++) p=p*y; return p-x;}
float DEI(float s, float d, int n, float x){ if(d-s<=0.0001) return s; else { float m=(s+d)/2; if(f(m,n,x)==0) return m; else if(f(m,n,x)<0) return DEI(m,d,n,x); else return DEI(s,m,n,x); }}
int main(){ int n; float x; cin>>n>>x; cout<<DEI(0,sqrt(x),n,x); return 0;}
Scrieti o functie minmax care sa determine elementul minim si elementul maxim dintr-un tablou cu elemente intregi folosind metoda divide et impera.
void minmax(int v[], int s, int d, int &minn, int &maxx){ if(s==d) minn=maxx=v[s]; else { int a,b,x,y; minmax(v,s,(s+d)/2,a,x); minmax(v,(s+d)/2+1,d,b,y); if(a<b) minn=a; else minn=b; if(x>y) maxx=x; else maxx=y; }}
Folosind metoda divide et impera, scrieti o functie care sa determine daca un tablou cu elemente intregi este ordonat crescator.
int ordon(int v[], int s, int d){ if(s==d) return 1; else if(ordon(v,s,(s+d)/2) && ordon(v,(s+d)/2+1,d) && v[(s+d)/2]<=v[(s+d)/2+1]) return 1; else return 0;}
Divide et impera
subproblemele (aflam maximul pentru fiecare din ele) iar solutia problemei va fi data de valoarea maxima dintre rezultatele celor doua subprobleme. -----------
Trebuie tiparita valoarea maxima dintre numerele retinute in vector de la i la j(initial i= 1, j=n). Pentru aceasta procedam astfel :daca i=j, valoare maxima va fi v[i] ;
contrar vom imparti vectorul in doi vectori (primul vector va contine componentele de la i la (i+j) div 2, al doilea va contine componentele de la ((i+j) div 2 +1 la j ) , rezolvam
< -----------
Maximul#include<iostream.h> int v[10],n; int max(int i ,int j) { int a,b; if (i==j) return v[i] ; else { a=max(i, (i+j)/2); b=max((i+j)/2+1,j); if (a>b) return a; else return b;} } main( ){ cout<<"n=";cin>>n; for (int i=1;i<=n;i++) {cout<<"v["<<i<<"]=";cin>>v[i]; } cout<<"max="<<max(1,n);}
108
Cautarea binara
#include<fstream>
using namespace std;ifstream fin("dateo.in");ofstream fout("dateo.out");
int main(){ int x,i,n,a[100],s,d,m,gasit=0; fin>>n; for(i=1;i<=n;i++) fin>>a[i]; fin>>x; s=1; d=n; while(s<=d && !gasit) { m=(s+d)/2; if(a[m]==x) gasit=1; else if(a[m]<x) s=m+1; else d=m-1; } if(gasit) fout<<m; else fout<<"Nu se gaseste"; fin.close(); fout.close(); return 0;}
Se citeste un numar real x. Sa se calculeze radical de ordinul 3 din x folosind un algoritm de tip Divide et impera.
#include<iostream>using namespace std;double r3(double x, double s, double d){ if(d-s<=0.0001) return d; else { double m=(s+d)/2; if(m*m*m<x) return r3(x,m,d); else return r3(x,s,m); } }
int main(){ double x; cin>>x; if(x>0) if(x<1) cout<<r3(x,0,1); else cout<<r3(x,0,x); else if(x>-1) cout<<r3(x,-1,0); else cout<<r3(x,x,0); system("pause"); return 0;}
Se citeste un vector cu n elemente numere naturale. Sa se determine elementul minim din vector folosind divide et impera.
#include<iostream>
using namespace std;
int min(int a[100],int s , int d){ if ( s == d ) return a[s]; else { int m = (s+d)/2; int m1 = min(a,s,m); int m2 = min(a,m+1,d); if ( m1 < m2 ) return m1; else return m2; }}
int main(){ int a[100]; int n ; cin>> n; for (int i = 0 ; i < n ;i++) cin>>a[i]; cout << min(a,1,n); system("pause"); return 0;}
Se citeste un vector cu n elemente numere naturale. Sa se calculeze suma elementelor vectorului folosind divide et impera.
#include<iostream>
using namespace std;
int suma(int a[100], int s, int d){ if(s==d) return a[s]; else return suma(a,s,(s+d)/2)+suma(a,(s+d)/2+1,d);}
int main(){ int a[100],n,i; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; cout<<suma(a,1,n); system("pause"); return 0;}
Turnurile Hanoi#include<fstream>using namespace std;ifstream fin("h.in");ofstream fout("h.out");
void hanoi(int n, char a, char b, char c,char t1[10], char t2[10], char t3[10]){ if(n>=1){hanoi(n-1,a,c,b,t1,t3,t2); int x=strlen(t2); t2[x]=t1[strlen(t1)-1]; t2[x+1]=0; strcpy(t1+strlen(t1)-1, t1+strlen(t1)); fout<<t1<<endl<<t2<<endl<<t3<<endl; fout<<a<<"->"<<b<<endl<<endl; hanoi(n-1,c,b,a,t3,t2,t1); } } -----------------------
Turnuri Hanoi Part2int main(){ char t1[10]="A", t2[10]="B", t3[10]="C"; int n; fin>>n; for(int i=n;i>=1;i--) t1[n-i+1]=i+'0'; t1[n+1]=0; hanoi(n,'A','B','C',t1,t2,t3); fin.close(); fout.close();}
Divide et impera