1. Problema damelor — enunt si idee
Solutia 1: col=[1, 3, 0, 2] . D . . . . . D D . . . . . D . Solutia 2: col=[2, 0, 3, 1] . . D . D . . . . . . D . D . .
Total: 2 solutii pentru 4x4. (Pentru 8x8 exista 92 solutii.)
k incercam fiecare coloana 0..n-1. Verificam daca plasarea e valida fata de toate damele deja puse. Daca da, continuam recursiv cu linia k+1. Daca nu gasim nicio coloana valida, revenim la linia precedenta.
linie in coloana coloana este invalida daca exista o linie anterioara l cu:
col[l] == coloana— aceeasi coloanaabs(col[l] - coloana) == abs(l - linie)— pe aceeasi diagonala
2. Implementare dame in Python
# Problema damelor - backtracking # col[i] = coloana damei de pe linia i (0-indexat) def dame(n): col = [0] * n # solutia curenta rezultate = [] def valid(linie, coloana): for l in range(linie): if col[l] == coloana: # aceeasi coloana return False if abs(col[l] - coloana) == abs(l - linie): # diagonala return False return True def back(linie): if linie == n: rezultate.append(col[:]) # copie a solutiei return for c in range(n): if valid(linie, c): col[linie] = c back(linie + 1) col[linie] = 0 # revenire back(0) return rezultate # Test n=4 sol = dame(4) print(f"Dame 4x4: {len(sol)} solutii") for s in sol: print(s) # Test n=8 sol8 = dame(8) print(f"Dame 8x8: {len(sol8)} solutii")
Dame 4x4: 2 solutii [1, 3, 0, 2] [2, 0, 3, 1] Dame 8x8: 92 solutii
3. Implementare dame in C++ EXCLUSIV INTENSIV
La profilul mat-info intensiv, acelasi algoritm se scrie in C++ cu tablouri statice globale si functie recursiva. Diferente fata de Python: tipuri explicite (int, bool), tablouri de marime fixa, abs() din <cstdlib>.
#include <iostream> #include <cstdlib> using namespace std; int n; int col[10]; // col[i] = coloana damei pe linia i int nr_sol = 0; bool valid(int linie, int coloana) { for (int l = 0; l < linie; l++) { if (col[l] == coloana) return false; if (abs(col[l] - coloana) == abs(l - linie)) return false; } return true; } void back(int linie) { if (linie == n) { nr_sol++; if (nr_sol <= 2) { cout << "Solutia " << nr_sol << ": "; for (int i = 0; i < n; i++) cout << col[i] << " "; cout << "\n"; } return; } for (int c = 0; c < n; c++) { if (valid(linie, c)) { col[linie] = c; back(linie + 1); col[linie] = 0; // revenire } } } int main() { n = 4; cout << "Dame 4x4:\n"; back(0); cout << "Total solutii: " << nr_sol << "\n"; return 0; }
Dame 4x4: Solutia 1: 1 3 0 2 Solutia 2: 2 0 3 1 Total solutii: 2
Acelasi rezultat ca versiunea Python. In C++, variabilele globale int col[10] si int nr_sol sunt initializate automat cu 0. Functia back() le acceseaza direct la orice nivel al recursiei, fara a le transmite ca parametri.
4. Rezolvarea labirintului prin backtracking
(0,0) la coltul dreapta-jos (n-1,m-1), miscandu-te in cele 4 directii (sus, jos, stanga, dreapta).
0 0 1 0 1 0 0 0 1 0 1 0 0 0 0 0
Start: (0,0), Stop: (3,3)
vizitat.
# Labirint backtracking - gaseste toate drumurile def labirint(grid): n = len(grid) m = len(grid[0]) vizitat = [[False]*m for _ in range(n)] drum = [] solutii = [] dx = [-1, 1, 0, 0] # sus, jos, stanga, dreapta dy = [0, 0, -1, 1] def back(x, y): if x < 0 or x >= n or y < 0 or y >= m: return # iesit din matrice if grid[x][y] == 1 or vizitat[x][y]: return # perete sau deja vizitat vizitat[x][y] = True drum.append((x, y)) if x == n-1 and y == m-1: solutii.append(drum[:]) # drum complet - salvam else: for i in range(4): back(x + dx[i], y + dy[i]) # exploreaza vecini drum.pop() vizitat[x][y] = False # revenire back(0, 0) return solutii grid = [ [0, 0, 1, 0], [1, 0, 0, 0], [1, 0, 1, 0], [0, 0, 0, 0] ] sol = labirint(grid) print(f"Labirint 4x4: {len(sol)} solutii") for i, s in enumerate(sol): print(f" Solutia {i+1}: {s}")
Labirint 4x4: 2 solutii Solutia 1: [(0, 0), (0, 1), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3)] Solutia 2: [(0, 0), (0, 1), (1, 1), (1, 2), (1, 3), (2, 3), (3, 3)]
gasit = [False] si opreste explorarea dupa prima solutie: if gasit[0]: return. Aceasta varianta este mult mai eficienta cand drumul exista.
vizitat[][] limiteaza drastic numarul de stari.
5. Colorarea unui graf cu k culori
1 -- 2 | | 4 -- 3 Muchii: 1-2, 2-3, 3-4, 4-1
# Colorarea unui graf - backtracking def colorare(n, adj, k): culoare = [0] * (n + 1) # culoare[i] = culoarea nodului i solutii = [] def valid(nod, c): for vecin in adj[nod]: if culoare[vecin] == c: return False return True def back(nod): if nod > n: solutii.append(culoare[1:n+1][:]) return for c in range(1, k + 1): if valid(nod, c): culoare[nod] = c back(nod + 1) culoare[nod] = 0 # revenire back(1) return solutii # Graf: patrat 1-2-3-4-1 n = 4 adj = {1: [2, 4], 2: [1, 3], 3: [2, 4], 4: [3, 1]} sol2 = colorare(n, adj, 2) print(f"Colorare patrat cu 2 culori: {len(sol2)} solutii") for s in sol2: print(s) sol3 = colorare(n, adj, 3) print(f"Colorare patrat cu 3 culori: {len(sol3)} solutii")
Colorare patrat cu 2 culori: 2 solutii [1, 2, 1, 2] [2, 1, 2, 1] Colorare patrat cu 3 culori: 18 solutii
6. Tipare comune si comparatie intre aplicatii
DAME LABIRINT COLORARE
-----------------------------------------------------------------
Stare curenta col[linie] (x, y) culoare[nod]
Parametru back linie (0..n-1) (x, y) coordonate nod (1..n)
Candidati coloane 0..n-1 4 directii (dx,dy) culori 1..k
Caz de baza linie == n (n-1, m-1) nod > n
Conditie valid coloana+diag. in matrice, vecini !=c
liber, nevizitat
Revenire col[linie]=0 pop drum, culoare[nod]=0
vizitat[x][y]=F
Complexitate ~O(n!) ~O(4^(n*m)) ~O(k^n)
-----------------------------------------------------------------
- Caz de baza: solutia e completa → salveaza/afiseaza,
return - Iterare candidati: pentru fiecare candidat posibil la pasul curent
- Verificare validitate: daca candidatul e valid in contextul curent
- Avansare: aplica candidatul, apeleaza recursiv cu pasul urmator
- Revenire: anuleaza candidatul (resetezi la 0 / False / scoate din drum)