Documente Academic
Documente Profesional
Documente Cultură
Introducere
Metoda backtracking poate fi aplicată în rezolvarea problemelor care respectă
următoarele condiții:
Exemplu
Să rezolvăm următoarea problemă folosind metoda backtracking. Să se afișeze
permutările mulțimii {1, 2, 3}.
o Un șir de numere reprezintă o permutare a unei mulțimi M dacă și numai dacă
conține fiecare element al mulțimii M o singură dată. Altfel spus, în cazul nostru:
are exact 3 elemente;
fiecare element este cuprins între 1 și 3;
elementele nu se repetă.
Formalizare
Pentru a putea realiza un algoritm backtracking pentru rezolvarea unei probleme trebuie
să răspundem la următoarele întrebări:
Algoritmul general
Metoda backtracking poate fi implementată iterativ sau recursiv. În ambele situații se se
folosește o structură de deate de tip stivă.
subprogram BACK(k)
┌ pentru fiecare element i din A[k] executa
│ x[k] ← i
│ ┌ daca OK(k) atunci
│ │ ┌ daca Solutie(k) atunci
│ │ │ Afisare(k)
│ │ │ altfel
│ │ │ BACK(k+1)
│ │ └■
│ └■
└■
sfarsit_subprogram
Observații:
o dacă parcurgem elementele lui A în ordine crescătoare vom obține soluții în ordine
lexicografică;
o dacă parcurgem elementele lui A în ordine descrescătoare vom obține soluții în ordine
invers lexicografică.
o
#include <fstream>
using namespace std;
De multe ori condițiile de existență a soluției sunt simple și nu se justifică scrierea unei
funcții pentru verificarea lor, ele putând fi verificate direct în funcția Back().
De cele mai multe ori, rezolvarea unei probleme folosind metoda backtracking constă în
următoarele:
GENERAREA PERMUTARILOR
Problema
Fie un număr natural n. Să se afișeze, în ordine lexicografică, permutările mulțimii {1,2,,
⋯,n}
Exemplu
Pentru n=3, se va afișa:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
Rezolvare
Bineînțeles, vom rezolva problema prin metoda backtracking. Vectorul soluție x[] va
reprezenta o permutare candidat. Să ne gândim care sunt proprietățile unei permutări,
pe care le va respecta și vectorul x[]:
condiții externe: x[k]∈{1,2,⋯,n}
condiții interne: x[k]∉{x[1],x[2],⋯,x[k−1]} pentru k∈{2,3,⋯,n}
condiții de existență a soluției: k=n
#include <iostream>
using namespace std;
int x[10] ,n;
void Afis()
{
for( int j=1;j<=n;j++)
cout<<x[j]<<" ";
cout<<endl;
}
int OK(int k){
for(int i=1;i<k;i++)
if(x[k]==x[i])
return 0;
return 1;
}
int Solutie(int k)
{ return k == n;}
Semnificația funcțiilor
void Afis(); afișează soluția curentă. Când se apelează, vectorul
soluție x are n elemente, reprezentând o permutare completă;
int OK(int k); verifică condițiile interne. La apel, x[k] tocmai a primit o
valoare conform condițiilor externe. Prin funcția OK() se va verifica dacă această
valoare este validă;
int Solutie(int k); verifică dacă avem o soluție completă. Acest lucru se
întâmplă când permutarea este completă – am dat o valoare corectă ultimului
element al tabloului, x[n], adică atunci când k=n;
void back(int k); – apelul acestei funcții dă valori posibile
elementului x[k] al vectorului soluție și le verifică:
o se parcurg valorile pe care le pot lua elementele vectorului, conform
condițiilor externe (în acest caz, 1..n);
se memorează în x[k] valoarea curentă;
dacă valoarea lui x[k] este corectă, conform condițiilor interne, se
verifică dacă avem o soluție completă. În caz afirmativ se afișează
această soluție, în caz contrar se trece la următorul element, prin
apelul recursiv;
o la finalul parcurgerii, se revine la elementul anterior al vectorului x, prin
revenirea din apelul recursiv.
Observații
#include <iostream>
using namespace std;
COMBINARI
4 2 => C(4,2)=4!/(2!*2!)=6
12 13 14 23 24 34
#include <iostream>
using namespace std;
int x[10] , n ,cnt=0,k;
void Afis()
{ cnt++;
for(int j = 1 ; j <= k ; j ++)
cout << x[j] << " ";
cout << endl;
}
void back(int pas){
for(int i = x[pas-1]+1 ; i <= n ; ++ i)
{
x[pas] = i;
if(pas < k)
back(pas + 1);
else
Afis();
}
}
int main(){
cin >> n>>k;
back(1);cout<<cnt<<endl;
return 0;
}
ARANJAMENTE
4 2 => A(4,2)=4!/2!=12
12 13 14 21 23 24
31 32 34 41 42 43
#include <iostream>
using namespace std;
int x[10] , n ,k,p[10];
void Afis()
{ for(int j = 1 ; j <= k ; j ++)
cout << x[j] << " ";
cout << endl;
}
void back(int pas){
for(int i = 1 ; i <= n ; ++ i)
{ if(p[i]==0)
{ p[i]=1;
x[pas] = i;
if(pas < k)
back(pas + 1);
else // pas==k
Afis();
p[i]=0;
}
}
int main(){
cin >> n>>k;
back(1);
return 0;
}
Probleme.
1. Se citesc 2 nr naturale n si m . Sa se afiseze in ordine lexicografica
toate submultimile de m elem din mult {1,2,....n} in care nu exista
doua elemnte pare alaturate.
#include <iostream>
using namespace std;
int x[10] , n ,k;
void Afis()
{ for(int i = 1 ; i <= k ; i ++)
cout << x[i] << " ";
cout << endl;
}
}}
}
int main(){
cin >> n>>k;
for(int i=1;i<=n;++i)
x[1]=i, back(2);
return 0;
}
ex 1 2 3
1
12
123
13
2
23
3
#include <iostream>
using namespace std;
int x[10] , n;
void Afis(int l)
{ for(int i = 1 ; i <= l ; i ++)
cout << x[i] << " ";
cout << endl;
}
}
}
int main(){
cin >> n;
back(1);
return 0;
}