Documente Academic
Documente Profesional
Documente Cultură
1. Metoda Greedy 2. Metoda Divide and Conquer(Tehnica divizrii) 3. Metoda Backtracking(Algoritmi cu revenire)
Greedy
Explicarea numelui
n limba englez cuvntul greedy nseamn lacom. Algoritmii de tip greedy sunt algoritmi lacomi: ei urmresc s construiasc ntr-un mod ct mai rapid soluia problemei. Algoritmii de tip greedy se caracterizeaz prin luarea unor decizii rapide care duc la gsirea unei soluii a problemei. Nu ntotdeauna asemenea decizii rapide conduc la o soluie optim, dar vom vedea c exist anumite tipuri de probleme unde se pot obine soluii optime sau foarte apropiate de optim.
Greedy
Principii
Metoda Greedy se aplic la acele probleme la care, dndu-se mulimea A a datelor de intrare, se cere s se determine o submulime B a sa, care trebuie s ndeplineasc anumite condiii pentru a fi acceptat ca soluie posibil. n general, exist mai multe soluii posibile. Dintre acestea se pot selecta, conform unui anumit criteriu, nite submulimi B* care reprezint soluii optime ale problemei. Scopul este acela de a gsi una dintre mulimile B*. Dac acest lucru nu este posibil, atunci scopul este gsirea unei mulimi B care s fie ct mai aproape de mulimile B*, conform criteriului de optimalitate impus. Soluiile posibile au urmtoarea proprietate: dac B este o soluie posibil atunci orice submulime a sa, inclusiv mulimea vid este, de asemenea, soluie posibil.
Greedy
Principii
Construirea mulimii B se face printr-un ir de decizii. Iniial se pornete cu mulimea vid (B = ). Fiecare decizie const n alegerea unui element din mulimea A, analiza lui i eventual introducerea lui n mulimea B. n funcie de modul n care se iau aceste decizii, mulimea B se va apropia mai mult sau mai puin de soluia optim B*. n cazul ideal vom avea B = B*. La fiecare pas se analizeaz cte un element din mulimea A i se decide dac s fie sau nu inclus n mulimea B care se construiete. Astfel se progreseaz de la cu un sir de mulimi intermediare (, B0, B1, B2, ...), pn cnd se obine o soluie final B.
Greedy
Strategii
Metoda Greedy nu urmrete s determine toate soluiile posibile ca s aleag apoi pe cea optim, conform criteriului de optimizare dat. O astfel de metod, care ar face cutare exhaustiv n spaiul soluiilor, necesit, de regul, un efort de calcul foarte mare. Metoda Greedy, n schimb, nu necesit nici timp de calcul, nici spaiu de memorie mare, comparativ cu metodele exacte. Pe baza proprietii enunate anterior, la fiecare pas al metodei exist o soluie posibil care se va mbogi cu un nou element, ales astfel nct irul soluiilor posibile s convearg spre soluia optim. Noua soluie "nghite" elementul cel mai "promitor".
Greedy
Strategia 1
Exist mai multe strategii prin care se poate implementa metoda Greedy. n continuare se prezint dou astfel de strategii care difer prin ordinea de efectuare a unor operaii. Se consider c mulimea datelor de intrare, A, are iniial n elemente. B reprezint, n orice moment, soluia posibil. Funcia logic posibil are valoarea true dac elementul selectat, transmis ca parametru, formeaz mpreun cu mulimea B o nou soluie posibil. Verificrile efectuate n aceast funcie trebuie s rezulte din enunul problemei. Iniial, B este mulimea vid. La fiecare pas al algoritmului se alege, ntr-un anumit fel, un element din A neales la paii precedeni (funcia alege). Se adaug acest nou element la soluia posibil anterioar, dac prin aceast adugare se obine tot o soluie posibil.
Greedy
Strategia 1
B = multimea vida for (i=0; i<n; i++) { x = alege( A); if (posibil( B ,x)) * adauga elementul x la multimea B; } Dificultatea la aceast prim variant const n scrierea funciei alege. Dac funcia alege este bine conceput, atunci putem fi siguri c soluia B gsit este o soluie foarte bun, apropiat de cea optim sau chiar optim. Dac funcia alege nu este foarte bine conceput, atunci soluia B gsit va fi doar o soluie posibil i nu va fi optim. => Criteriul de selecie implementat n funcia alege, o poate apropia mai mult sau mai puin de soluia optim B*.
Greedy
Strategia 2
n anumite cazuri, ordinea n care trebuie considerate elementele din mulimea A se poate stabili de la nceput (funcia prelucreaza), obinndu-se, pe baza mulimii A, un vector V cu n componente : B = multimea vida; prelucreaza(A,V); for (i=0; i<n; i++) { x = V[i]; if (posibil(B,x)) * adauga elementul x la multimea B; } La a doua variant, dificultatea funciei alege nu a disprut, ci s-a transferat funciei prelucreaza. Dac prelucrarea mulimii A este bine fcut, atunci se poate ajunge la o soluie optim. Altfel se va obine doar o soluie posibil, mai mult sau mai puin apropiat de optim.
Greedy
Probleme de optimizare
Un exemplu tipic de aplicare al metodei Greedy l reprezint problemele de optimizare. n acest tip de probleme, de regul, se cere s se selecteze din datele de intrare acele elemente care maximizeaz o funcie de cost. Ideea general a metodei este de a alege la fiecare pas acel element care determin cea mai mare cretere a acestei funcii. Neanaliznd influena corelaiei dintre elemente asupra funciei de cost, metoda nu poate garanta c aceste maximizri locale, succesive, conduc ntotdeauna la maximul global ateptat. Aceasta nseamn c sunt situaii n care metoda Greedy nu genereaz soluia optim, dei aceasta exist.
Greedy
Probleme de optimizare - exemplu
Se d o mulime X = {x0, ..., xn-1} cu elemente reale. Se cere s se determine o submulime Y a sa astfel nct f = y s fie maxim.
yY
Se observ c o soluie posibil este orice submulime a lui X avnd numai elemente pozitive, iar soluia optim este cea mai cuprinztoare dintre aceste submulimi, adic aceea care include toate elementele pozitive din X. Se opteaz pentru strategia 2 a metodei Greedy. Organiznd de la bun nceput X i Y ca vectori, funcia prelucreaza nu mai este necesar n acest caz. Iniializarea lui B pe se reduce la atribuirea k = 0. Funcia posibil este reprezentat prin condiia x[i] > 0 iar operaia de obinere a unei noi soluii posibile, prin adugarea unui element din intrare este dat de operaiile y[k] = x_ales i k++.
Greedy
Probleme de optimizare - exemplu
k = 0; suma = 0; for (i=0; (i<N) && (x[i]>0); i++) { x_ales = x[i]; y[k] = x_ales; k++; suma += x_ales; }
Greedy
Interclasarea optimal a mai multor iruri
Se dau n iruri S1, S2, ..., Sn de lungimi l1, l2, ..., ln. n cadrul fiecrui ir elementele sunt ordonate cresctor. Se cere s se obin un ir S cu l1+l2+...+ln elemente, ordonate de asemenea cresctor, coninnd elementele cumulate ale celor n iruri iniiale. Se dispune de o funcie capabil s interclaseze dou iruri ordonate care i se transmit ca parametri. Se cere, de asemenea, ca programul realizat s fie optim din punct de vedere al timpului total necesar pentru interclasare. Optimizarea cerut se va reflecta la nivelul programului principal i const n determinarea ordinii optime n care trebuie efectuate interclasrile astfel nct timpul total s fie minim.
Greedy
Interclasarea optimal a mai multor iruri
Din teoria legat de interclasarea irurilor se cunoate faptul c timpul necesar pentru interclasarea a dou iruri ordonate, A i B, de lungimi a i resp. b, este proporional cu a+b {O(a+b)}, rezultat din faptul c sunt necesare a+b deplasri de elemente. Exemplu : L = (90, 70, 40, 10) t1 = (90+70) +(160+40) +(200+10) = 570 depl. t2 = (10+40) +(50+70) +(120+90) = 380 depl. Soluie Greedy: se interclaseaz cele mai scurte dou iruri, rezultnd n-1 iruri; se interclaseaz apoi cele mai scurte dou iruri dintre cele rmase . a. m. d.
Greedy
Problema comis-voiajorului (TSP)
TSP - Traveling Salesman Problem Se consider n puncte distincte. Se furnizeaz ca date de intrare distanele dintre aceste puncte. Se cere s se determine un drum care s porneasc dintr-un punct oarecare, s treac o singur dat prin toate celelalte i s se ntoarc n punctul iniial, astfel nct lungimea drumului s fie minim. Toi algoritmii care conduc la soluia optim n aceast problem necesit timp de calcul exponenial {O(2n)}. Un algoritm care utilizeaz metoda Greedy (neoptimal) necesit pentru determinarea soluiei un timp polinomial {O(n2)}. Ideea pentru Greedy: se adaug ntotdeauna la drum acel punct pentru care distana fa de punctul adugat anterior este minim i nu este nc legat. Dup ce s-au cuprins n drum toate punctele se face legtura ntre ultimul punct i primul.
Greedy
Problema comis-voiajorului (TSP)
Exemplu :
7
4
2 5
1
2
1
3
Greedy
Problema comis-voiajorului (TSP)
7
4
2 5
1
2
1
3
nod de plecare : 1 lungime drum = 13
Greedy
Problema comis-voiajorului (TSP)
7
4
2 5
1
2
1
3
nod de plecare : 3 lungime drum = 9
Greedy
Problema comis-voiajorului (TSP)
Distanele ntre orae le memorm ntr-un tablou bidimensional d. Distana ntre oraele (i,j) va fi reprezentat de elementul di,j al matricii. n termeni Greedy, mulimea iniial A este mulimea tuturor perechilor de orae. Mulimea B care trebuie gsit va conine o parte din aceste perechi de orae, i anume acele perechi care nlnuite s formeze un drum ce trece prin toate oraele.
Greedy
Problema comis-voiajorului (TSP)
n implementare nu vom lucra cu mulimea A sub aceast form explicit de perechi de orae, ci vom folosi matricea distanelor d. De asemenea drumul comis-voiajorului nu l vom pstra sub form de perechi de orae, ci sub forma unui sir al oraelor, numit drum. Care va conine indicii oraelor parcurse, n ordinea parcurgerii. Pentru a ti care orae au fost parcurse, facem o marcare logic a oraelor folosind un tablou unidimensional vizitat. Elementele din acest tablou care au valoarea 1 reprezint orae vizitate.
Greedy
Problema comis-voiajorului (TSP)
#include <stdio.h> #define N_MAX 30 /* Numarul maxim de orase. */ #define MINIM 10000 /* Constanta care se foloseste ca valoare de initializare la cautarea minimului. */ int n; /* Numarul de orase. */ int d[N_MAX][N_MAX]; /* Matricea distantelor dintre orase. */ int drum[N_MAX]; /* Drumul comis voiajorului. Contine indicii oraselor in ordinea in care sunt ele parcurse. */ int vizitat[N_MAX]; /* Vector care memoreaza ce orase au fost vizitate. */
Greedy
Problema comis-voiajorului (TSP)
/*Functia alege urmatorul urmatorul oras care sa fie vizitat. */ void alege(int ultimul, int *min, int *j_min) { int j; /* Cautam drumul minim pana la orasele neparcurse inca. */ *min = MINIM; *j_min = -1; for (j=0; j<n; j++) if (!vizitat[ j ]) { if (d[ ultimul ][ j ] < *min) { *min = d[ ultimul ][ j ]; *j_min = j;} } }
Greedy
Problema comis-voiajorului (TSP)
int main(void) { FILE *fin; int i, j, count, cost, min, j_min; fin = fopen("comis.in", "rt"); if (!fin) { printf("Eroare: nu pot deschide fisierul.\n"); return -1; } fscanf(fin, "%d", &n); /* Citim datele din fisier. */ for (i=0; i<n; i++) for (j=0; j<n; j++) fscanf( fin, "%d", &(d[ i ][ j ]));
Greedy
Problema comis-voiajorului (TSP)
printf("Avem %d orase.\n", n); printf("Distantele dintre orase sunt:\n"); for (i=0; i<n; i++) { for (j=0; j<n; j++) printf("%d ", d[ i ][ j ]); printf("\n"); } printf("\n"); for (i=0; i<n; i++) vizitat[i] = 0; /* Initial nici un oras nu este vizitat. */ /* Primul oras vizitat este cel cu numarul "0". */ drum[0] = 0; vizitat[0] = 1; count = 1; cost = 0;
Greedy
Problema comis-voiajorului (TSP)
/* Parcurgem restul de n-1 orase. */ for (i=0; i<n-1; i++) { /* Alegem urmatorul oras care sa fie vizitat. */ alege(drum[count-1], &min, &j_min); printf("Am ales drumul (%d, %d) de cost %d.\n", drum[count-1], j_min, min); drum[count] = j_min; vizitat [j_min ] = 1; count++; cost += min; }
Greedy
Problema comis-voiajorului (TSP)
/* Parcurgem drumul de la ultimul oras vizitat catre primul oras si actualizam costul total. */ cost += d[drum[n-1]][0]; /* Afisam drumul parcurs. */ printf("\nDrumul are costul %d si este:\n", cost); for (i=0; i<n; i++) printf("%d ", drum[i]); printf("0\n"); return 0; }
Greedy
Problema comis-voiajorului (TSP)
Rezolvarea problemei comis-voiajorului, prin metoda prezentat, poate fi mbuntit dac se repet algoritmul dat i pentru alte puncte iniiale (eventual pentru toate n), reinndu-se varianta de drum cu lungime minim. Mai mult, dac pentru un anumit punct iniial se ajunge n situaia ca lungimea drumului s depeasc lungimea minim de pn atunci, se poate abandona tratarea acelui lan, trecndu-se la alt punct iniial. Astfel, timpul cerut de aceast nou variant este cel mult O(n3). Metoda prezentat pentru rezolvarea problemei comis-voiajorului se ncadreaz n categoria algoritmilor euristici. Un algoritm este euristic dac furnizeaz soluii suficient de bune, dar nu neaprat optime, ntr-un timp rezonabil, mai mic dect cel necesar oricrui algoritm exact, cunoscut.
Greedy
Problema conectrii oraelor cu cost minim
Se dau un numr de n orae. Pentru diferite perechi de orae (i, j) i=1, 2, ... n i j=1, 2, ... n, nu neaprat pentru toate perechile posibile, se furnizeaz, ca date de intrare, costurile legrii lor directe (lungimea drumului, lungimea sau costul liniei telefonice de legtur, durata drumului dintre cele dou orae etc.). Se cere s se construiasc o reea prin care fiecare ora s fie legat cu toate celelalte direct sau indirect, astfel nct costul legturilor s fie minim. Se poate demonstra c soluia cerut este un arbore (eliminnd ciclurile se pstreaz condiiile problemei i costul este, evident, mai mic). Problema se mai numete i problema arborelui parial de cost minim (Minimum Spanning Tree) i are un grad mare de generalitate : orice problem n care soluia este un arbore i funcia de cost este ataat tranziiilor (muchiilor) n arbore.
Greedy
Problema conectrii oraelor cu cost minim
O soluie pentru construirea arborelui parial de cost minim, care se bazeaz pe metoda Greedy, este algoritmul lui Prim. Ideea algoritmului lui Prim : se pornete dintr-un ora oarecare sau de la muchia de cost minim care leag, de exemplu, cele mai apropiate dou orae. Apoi, se adaug n mod repetat, muchia de cost minim dintre cele rmase (nealese anterior) i care nu formeaz cu precedentele un ciclu, adic se adaug la reea acel ora, dintre cele nelegate, situat la cea mai mic distan fa de unul (oarecare) dintre oraele legate anterior. Se poate demonstra c arborele construit prin aceast strategie este ntr-adevr de cost minim.
Greedy
Problema conectrii oraelor cu cost minim
S considerm spre exemplu o reea de 7 orae numerotate de la 0 la 6. Costurile de conectare a oraelor sunt redate n figur.
Arborele minim este redat cu linii ngroate. El a fost construit pas cu pas, conform procedeului descris mai sus. Iniial arborele a fost vid. La primul pas s-a adugat un nod arbitrar, i anume nodul 0.
Metoda Backtracking
Algoritmi cu revenire explicarea numelui
Pentru a nelege semnificaia cuvntului backtracking vom reda definiia din Cambridge Online Dictionary, http://dictionary.cambridge.org/ : to go back along a path you have just followed Ideea de baz este aceea de revenire pe calea parcurs. Algoritmii de tip backtracking exploreaz spaiul soluiilor n mod exhaustiv, pe toate cile posibile. Atunci cnd pe calea curent de explorare se constat c nu mai sunt anse s se ajung la o soluie valid, se revine cu un pas napoi i se abordeaz o alt cale de explorare. n concluzie, metoda Backtracking const n efectuarea unor ncercri repetate, n vederea gsirii soluiilor, cu posibilitatea revenirii n caz de eec.
Metoda Backtracking
Algoritmi cu revenire - principii
Soluia se poate reprezenta sub forma unui vector X=(x0,x1, , xn-1), XS = S0 xS1x x Sn-1, unde mulimile S0, , Sn-1 sunt mulimi finite. Pentru fiecare problem concret sunt date anumite relaii ntre componentele x0,x1, , xn-1 ale vectorului X, numite condiii interne. Mulimea S reprezint spaiul soluiilor posibile. Soluiile posibile care satisfac condiiile interne se numesc soluii rezultat. n continuare, exprimm condiiile care trebuie satisfcute sub forma unei funcii logice notat: Solutie(x0,x1,...,xn-1). Un element X=(x0, x1, ..., xn-1) S este soluie a problemei dac funcia Solutie aplicat componentelor lui X va returna valoarea true.
Metoda Backtracking
Algoritmi cu revenire - principii
Scopul algoritmului concret poate s fie determinarea unei soluii rezultat sau a tuturor soluiilor rezultat, fie n scopul afirii lor, fie pentru a alege una optim din punctul de vedere al unor criterii de optimizare (minimizare sau maximizare). O metod simpl de selectare a soluiilor rezultat este aceea de a genera toate soluiile posibile i de a verifica satisfacerea condiiilor interne (cutare exhaustiv). Aceast metod necesit ns un timp de execuie foarte mare i nu se aplic dect rar n practic.
Metoda Backtracking
Algoritmi cu revenire - principii
Un algoritm backtracking performant, ca i n cazul Greedy de altfel, evit generarea tuturor soluiilor posibile. n acest scop, elementele vectorului X primesc, pe rnd i n ordine, valori. Dup asocierea unei valori lui xk se verific ndeplinirea unor condiii de continuare pentru secvena (x0, , xk) i numai apoi se trece la ncercarea de asociere a unei valori pentru xk+1: funcia Continuare(x0, x1, ..., xk) . Nendeplinirea acestor condiii ne arat, nc din aceast faz, c soluia final nu poate fi o soluie rezultat. n cazul unui eec la aceast verificare, se alege o alt valoare pentru xk Sk sau, dac Sk a fost epuizat, se micoreaz k cu o unitate i procesul de alegere se repet.
Metoda Backtracking
Procedura general - pseudocod
k = 0; while (k >= 0){ do { * alege urmatorul x[k] din multimea S[k]; * evalueaza Continuare(x[0], x[1], ..., x[k]); } while ( !Continuare(x[0], x[1], ..., x[k]) && (* mai sunt elemente de ales din multimea S[k]) ); if (Continuare(x[0], x[1], ..., x[k])) { if (k == n-1) { if (Solutie(x[0], x[1], ..., x[n-1])) * afiseaza solutie; } else { k = k + 1; } } else { k = k 1; } }
Metoda Backtracking
Algoritmi cu revenire - caracteristici
n concluzie: Numele metodei (algoritmi cu revenire) provine de la revenirile care se efectueaz n caz de eec. Condiiile de continuare deriv din condiiile interne. Alegerea optim a condiiilor de continuare poate determina reducerea numrului de calcule (ncercri) care urmeaz s fie efectuate (viteza programului). Acest proces de ncercri repetate i revenire n caz de eec (cu reluarea altei valori i continuare) se exprim n mod natural i n manier recursiv.
Metoda Backtracking
Soluia recursiv
Se consider c numrul elementelor care se pot examina la fiecare apel (cardinalitatea multimilor Sk) n vederea adugrii lor la soluie, este fix (m), iar numrul componentelor soluiei este de asemenea fix (n) : void Incearca (int k) { int i; for(i=0; i<m; i++) { * selecteaz elementul nr.i; if (* este acceptabil) { * nregistreaza elementul selectat; if (k<n-1) Incearca (k+1); else * tiparete soluie; * terge nregistrarea;} } }
Metoda Backtracking
Problema celor 8 regine (Eight Queens)
Se cere s se realizeze programul care s plaseze opt regine pe o tabl de ah, astfel nct nici una dintre ele s nu le amenine pe celelalte. La jocul de ah, o regin amenin pe linii, coloane i diagonale, pe orice distan. Aceast problem a fost investigat de Carl Friedrich Gauss n 1850 (care ns nu a rezolvat-o complet). Nici pn n prezent problema nu are o soluie analitic satisfctoare. n schimb ea poate fi rezolvat prin ncercri, necesitnd o mare cantitate de munc, rbdare i acuratee (condiii n care calculatorul se descurc excelent). Problema are 92 de soluii din care, din motive de simetrie, doar 12 sunt diferite. Problema poate fi uor extins pentru n regine plasate pe o tabl ptrat cu n linii i n coloane.
Metoda Backtracking
8 regine rezolvare
Pe fiecare linie sau coloan de pe tabl se va afla o singur regin. Se va parcurge tabla de ah linie cu linie (k=0..7), iar n cadrul unei linii coloan cu coloan (i=0..7) i se vor plasa reginele n acele ptrate care nu sunt n priza reginelor plasate anterior. Pentru parcurgerea tablei se va utiliza tehnica backtracking. Deoarece pe fiecare linie a tablei de ah se poate gsi exact o regin, o soluie rezultat se poate reprezenta sub forma unui vector C = (c0,..., c7) unde ck reprezint coloana pe care se afl regina de pe linia k (ck{0, ,7}). Spaiul soluiilor posibile este produsul cartezian S = C C C C C C C C. Condiiile interne, rezult din regulile ahului i sunt reprezentate de faptul c dou dame nu se pot afla pe o aceeai coloan sau o aceeai diagonal.
Metoda Backtracking
8 regine organizarea tablei de ah
Tabla de ah:
0 0 1 1
i
2 3 4 5 6 7
2 3 4 5 6 7
Metoda Backtracking
8 regine condiiile interne
Funcia Solutie trebuie s verifice dac nu exist regine care se afl pe aceeai coloan sau dac nu cumva exist regine care se atac pe diagonal. Verificarea este simpl. Trebuie s verificm c ntre elementele (c0, c1, c2, c3, c4, c5, c6, c7) nu exist dou care au aceeai valoare. Aceasta ar nsemna c avem dou regine pe aceeai coloan. Apoi mai trebuie s verificm c i,k {0, 1, 2, 3, 4, 5, 6, 7}, |i-k| |ci-ck|. Aceasta este condiia ca s nu existe dou regine care se atac pe diagonal. Verificri similare vor fi efectuate pe parcurs de funcia Continuare.
8 Regine
#include <stdio.h> #include <conio.h> #include <stdlib.h> #define N 8 #define INVALID -1 int main(void) { int c[N]; int k, i; int continuare, ataca; int count = 0; // Numaram si cate solutii sunt gasite for (i=0; i<N; i++) c[i] = INVALID; //Initializam toate elem. din vectorul c
Implementarea programului
8 Regine
Implementarea programului
k = 0; while (k >= 0) { /* Ne vom opri atunci cand am epuizat elem. din multimea C[k] sau atunci cand intalnim un element pentru care functia Continuare returneaza true. */ do { if (c[k] == INVALID) // nu s-a incercat plasarea reginei de pe linia k c[k] = 0; // plasam regina de pe linia "k" pe coloana 0 else // incercam sa plasam regina pe urmatoarea col. c[k]++; /* Daca nu am depasit numarul de coloane de pe linie, atunci trecem la evaluarea functiei Continuare. */
8 Regine
Implementarea programului
if (c[k] < N) { /* Ne asiguram ca regina pe care vrem sa o plasam pe linia "k" si coloana "c[k]" nu ataca nici una din reginele deja plasate*/ ataca = 0; for (i=0; !ataca && (i<k); i++) { /* Verificam daca mai exista o regina pe aceeasi coloana*/ if (c[i] == c[k]) ataca = 1; /*Verificam daca noua regina ataca alta, pe diagonala*/ else if (abs(i-k) == abs(c[i]-c[k])) ataca = 1; }
8 Regine
Implementarea programului
/* Daca noua regina nu ataca nici una din reginele plasate anterior, atunci functia Continuare returneaza true(1), altfel returneaza false (0) */ if (!ataca) continuare = 1; else continuare = 0; } /* Daca s-a depasit numarul coloanelor de pe o linie, functia Continuare returneaza automat false. */ else continuare = 0; } while (!continuare && (c[k] < N));
8 Regine
Implementarea programului
/* Daca am obtinut true (1), din functia Continuare, atunci consideram regina plasata si continuam algoritmul*/ if (continuare) { /* Daca am plasat toate N reginele, atunci afisam solutia gasita. */ if (k == N-1) { for (i=0; i<N; i++) printf("%d ", c[i]); printf("\n"); count++; } else k++; }
8 Regine
Implementarea programului
/* S-au epuizat toate variantele de plasare a reginei de pe linia k. Marcam cu INVALID elementul c[k] si revenim cu un pas inapoi pe calea de cautare, la regina k-1. */ else { c[k] = INVALID; k--; } } printf("%d solutii\n", count); return 0; }
Metoda Backtracking
8 regine algoritmul recursiv
void Incearca(int k){ int i= -1; do { i++; Succes =regina poate fi pusa in pozitia (k,i) if (Succes){ Ocupa; /*pune regina*/ C[k] = i; /*memoreaza coloana*/ if (k<7) Incearca(k+1); else Tipareste; Elibereaza; /*ia regina*/ }} while (i<7); }
Metoda Backtracking
Circuitului calului (Knights Tour)
Fiind dat o tabl ptrat cu n X n elemente, se cere s se realizeze programul C pentru gsirea traseului care trece prin toate elementele tablei, ncepnd cu cel de coordonate (i,j), utiliznd sritura calului dat de regulile ahului. Prin fiecare element se va trece o singur dat. Operaia esenial pe care o are de rezolvat algoritmul este executarea unei micri urmtoare sau constatarea c nu mai este posibil o astfel de micare i revenirea la micarea anterioar. Caracteristica esenial a acestui algoritm este aceea c nainteaz spre soluia final pas cu pas, ncercnd i nregistrnd drumul parcurs. Dac la un moment dat se observ c drumul ales nu conduce la soluia dorit i se blocheaz, se revine tergnd nregistrrile pailor pn la proximul punct care permite o nou alternativ de drum.
Metoda Backtracking
Circuitului calului structurile de date Pentru o tabl de dimensiune N vom memora soluiile ntr-un vector, c, de lungime N*N. Fiecare element din vector va fi la rndul lui un vector cu dou elemente, primul element va memora linia de pe tabl, iar al doilea element va memora coloana de pe tabl: int c[N*N][2]; count numrul de soluii gsite
Metoda Backtracking
Circuitului calului sritura
Noile coordonate, pentru o sritur, se calculeaz din cele curente adunnd nite valori fixe 1, 2, nregistrate n tablourile dx i dy, i care definesc cele opt micri viitoare (k=0..7) posibile dintr-un punct oarecare (x,y) :
6 7 5 4 C 0 1 2 3
u = x + dx[k] v = y + dy[k]
Metoda Backtracking
Circuitului calului programul
#include <stdio.h> #include <conio.h> #define N 5 int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; int dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; int c[N*N][2]; int count = 0;
Metoda Backtracking
Circuitului calului programul
void Incearca(int pas) { int i, j, continuare; if (pas == N*N) { for (i=0; i<pas; i++) printf("(%d,%d) ", c[i][0], c[i][1]); printf("\n"); count++; }
Metoda Backtracking
Circuitului calului programul
else for (i=0; i<8; i++) { c[pas][0] = c[pas-1][0] + dy[i]; c[pas][1] = c[pas-1][1] + dx[i]; if ((c[pas][0]>=0) && (c[pas][0]<N) && (c[pas][1]>=0) && (c[pas][1]<N)) { continuare = 1; for (j=0; continuare && (j<pas); j++) if ((c[j][0]== c[pas][0]) && (c[j][1] == c[pas][1])) continuare = 0; if (continuare) Incearca(pas+1); } } }
Metoda Backtracking
Circuitului calului programul
int main(void){ int i,j; for (i=0; i<N; i++) for (j=0; j<N; j++) { c[0][0] = i; c[0][1] = j; Incearca(1); } printf("%d solutii\n", count); return 0; }