Documente Academic
Documente Profesional
Documente Cultură
Backtracking
Backtracking
PROIECT ATESTAT
INFORMATICA
TEMA:
Metoda
backtracking
CUPRINS
Prezentarea generala .
pag.4 Exemple de implementare a
metodei pag. 6
Probleme si exercitii
. pag.24
Bibliografie .
pag.34
1.Prezentare general
Imaginai-v c astzi este ziua vostr i avei invitai. Aranjai o mas
frumoas, apoi v gndii cum s v aezai invitaii la mas. Ai vrea s tii toate
posibilitile de aezare a invitailor la mas, dar realizai n acelai timp c trebuie s
inei seama i de preferinele lor. Printre invitai exist anumite simpatii dar i unele
antipatii, de care dorii neaprat s inei seama, pentru ca petrecerea s fie o bucurie
pentru toi.
S ne gndim cum procedai pentru a identifica toate posibilitile de a plasa
invitaii la mas. ncepei prin a scrie nite cartonae cu numele invitailor.
Alegei un invitat.
Pentru a-l alege pe al doilea, selectai din mulimea cartonaelor rmase un alt
invitat. Dac tii c cele dou persoane nu se agreeaz, renuntai la cartonaul lui i
alegei altul i aa mai departe.
Se poate ntmpla ca la un moment dat, cnd vrei s alegei cartonaul unui
invitat s constatai c nici unul dintre invitaii rmai nu se potrivete cu ultima
persoan slectat pn acum. Cum procedai?
Schimbai ultimul invitat plasat cu un invitat dintre cei rmai i ncercai din
nou, dac nici aa nu reuiti, schimbai penultimul invitat cu alcineva i ncercai din
nou i aa mai departe pn cnd reuii s plasati toi invitaii. nseamn c ai
obinut o soluie.
Pentru a obine toate celelalte soluii, nu v rmne dect s o luai de la
nceput.
Avei
cam
mult
de
muncit,
iar
dac
numrul
invitailor
este
void BK(int k)
//k-poziia din vector care se completeaz
{int i;
for (i=1; i<=nr_elemente_Sk; i++)
//parcurge elementele mulimii Sk
{ v[k]=i;
//selecteaz un element din mulime
if (validare(k)==1)
//valideaz condiiile de continuare ale problemei
{ if (solutie(k)==1)
//verific dac s-a obinut o soluie
afisare(k);
//afieaz soluia
else
BK(k+1);
//reapeleaz functia pentru poziia k+1
}
}
//dac nu mai exist nici un element neselectat n mulimea Sk,
}
//se nchide nivelul de stiv i astfel se revine pe poziia k-1 a
//vectorului
//execuia funciei se ncheie, dup ce s-au nchis toate nivelurile stivei, nseamn c n vectorul v nu
mai poate fi selectat nici un elemente din multimile Sk
3.
v
1
k=3
2
1
3
k
3
1
2
3 element
incorect (se repet)
v
1
k=3
2
2
k
1
2
element incorect (se repet)
v
k=3
1
2
3
k
1
2
3
k=3
s-a obinut o soluie
se nchide ultimul nivel de stiv pentru
c nu mai sunt elemente n ultima
mulime
v
k=2
1
3
k
1
2
3
v
k=3
1
3
1
k
1
2
element incorect (se repet)
v
1
3
2
k
1
2
k=3
s-a obinut o soluie
v
k=3
1
3
3
k
1
2
3
element incorect (se repet)
v
k=2
1
3
k
1
2
3
v
k=1
2
k
1
2
3
se repet aceiai pai construindu-se
soluiile urmtoare
STIVA
i=1
STIVA
i=1 i=1
STIVA
i=1,2 i=1
STIVA
i=1
i=1,2
i=1
STIVA
i=1,2
i=1,2
i=1
STIVA
i=1,2,3
i=1,2
i=1
STIVA
i=1,2,3
i=1
STIVA
i=1
i=1,2,3
i=1
STIVA
i=1,2
i=1,2,3
i=1
STIVA
i=1,2,3
i=1,2,3
i=1
STIVA
i=1,2,3
i=1
STIVA
i=1,2
#include <iostream.h> //
PERMUTRI
const MAX=20;
int n,v[MAX] ;
//n-nr. de elemente, v[20]-vectorul n care construim soluia
int valid(int k); int
solutie(int k); void
afisare(int k); void
BK(int k);
int main()
{cout<<"n= ";cin>>n; //se citete n
BK(1);
return 0;
//apelm funcia BK pentru completarea poziiei 1din vectorul v
}
void BK(int k)
{int i;
//i-elementul selectat din multimea Sk, trebuie sa fie variabil local, pentru
// a se memora pe stiv
for (i=1;i<=n;i++)
//parcurgem elementele mulimii Sk
{v[k]=i;
//selectm un element din mulimea Sk
if (valid(k))
//verificm dac eelementul ales ndeplinete condiiile de continuare
{if (solutie(k))
//verificm dac am obinut o soluie
afisare(k);
//se afieaz soluia obinut
else
BK(k+1);
//reapemm funcia pentru poziia k+1 din vectorul v
}
}
}
int valid(int k)
//verificm condiiile de continuare
{int i;
for (i=1;i<=k-1;i++) //comparm fiecare element din vectorul v cu ultimul element selectat
if (v[i]==v[k])
//deoarece ntr-o permutare elementele nu au voie s se repete,
return 0;
//returnm 0 n cazul n care elementul selectat, a mai fost selectat o dat
return 1;
//returnm 1 n cazul n care elementul nu mai apare n vector
}
int solutie(int k)
//verificm dac am obinut o soluie
{if (k==n)
//am obinut o permutare, dac am reuit s depunem n vector n elemente
return 1;
return 0;
}
void afisare(int k)
//afieaz coninutul vectorului v
{int i;
for (i=1;i<=k;i++)
cout<<v[i]<<" ";
cout<<endl;
2. PRODUS CARTEZIAN
Se dau n mulimi, ca cele de mai jos:
S1={1,2,3,...,w1}
S2={1,2,3,...,w2}
.........................
Sn={1,2,3,...,wn}
Se cere s se gnereze produsul lor cartezian.
Exemplu:
pemtru n=3 i urmroarele mulimi
S1={1,2}
w1=2
S2={1,2,3}
w2=3
S3={1,2}
w3=2
#include <iostream.h>
#include <fstream.h>
const MAX=20;
int n,v[MAX],w[MAX];
void BK(int k);
void citire();
void afisare(int k);
int solutie(int k);
void main()
{citire();
BK(1);
}
void BK(int k)
{int i;
for (i=1;i<=w[k];i++)
{v[k]=i;
if (solutie(k))
afisare(k);
else
BK(k+1);
}
}
void citire()
{int i;
ifstream f("prod.in");
f>>n;
for(i=1;i<=n;i++)
f>>w[i];
f.close();
}
int solutie(int k)
{if (k==n)
return 1;
return 0;
}
void afisare(int k)
{int i;
for (i=1;i<=k;i++)
cout<<v[i]<<" ";
cout<<endl;
}
//
PRODUS CARTEZIAN
//citire date
//apelm funcia BK pentru selectarea primului element n v
//funcia becktreacking
//parcurgem mulimea Sk ={1,2,3,...,w k}
//selectm elementul i din mulimea Sk
//nu avem funcie de validare- nu avem condiii de continuare
//verificm dac am obinut o soluie
//afim soluia
//reapelm funcia BK pentru completarea poziiei urmtoare n
// vectorul v
//se nchide un nivel de stiv si astfel se ajunge la poziia k-1 n v
//citirea datelor
//se citete numrul de mulimi
//se citete numrul de elemente al fiecrei mulimi
//funcia soluie determin momentul n care se ajunge la o soluie
//obinem o soluie dac am dpus n vectorul v, n elemente
//afueaz o soluie
3. ARANJAMENTE
Se citesc n i p numere naturale cu p<=n. Sa se genereze toate aranjamentle
de n elemente luate cte p.
Exemplu pentru n=3, p=2
(1,2), (1,3), (2,1), (2,3), (3,1), (3,2)
Vom genera pe rnd soluiile problemei n vectorul v=(v1,v2,v3,...,vn), unde
vkSk.
S facem urmtoarele observaii:
1. pentru aceast problem toate mulimile Sk sunt identice, Sk={1,2,3,....,n}.
2. la pasul k selectm un element din mulimea Sk.
ntruct n cadrul unei aranjri, elementele nu au voie s se repete
aceast condiie reprezent condiia de continuare a problemei.
3. Oinem o soluie n momentul n care completm vectorul cu p elemente.
S observm c problema generrii aranjamentelor, nu difer prea mult de problema
generrii permutrilor. Singura deosebire pe care o sesizm este aceea c obinem o
soluie n momentul n care am plasat n vector p elemente.
Prin urmare, n cadrul programului pentru generarea permutrilor trebuie sa
modificm o singur funcie i anume funcia soluie, astfel:
int solutie(int k)
{if (k==p)
return 1;
return 0;
}
4. COMBINRI
Se citesc n i p numere naturale cu p<=n. S se genereze toate combinrile
de n elemente luate cte p.
Exemplu pentru n=3, p=2.
obinem
facem
urmtoarele
observaii:
1. Pentru aceast problem toate mulimile Sk sunt identice, Sk={1,2,3,....,n}.
La pasul k selectm un element din mulimea
Sk.
2. n cadrul unei combinri elementele nu au voie s se repete.
S mai observm i faptul c dac la un moment dat am generat de exemplu
soluia (1,2), combinarea (2,1) nu mai poate fi luat n considerare, ea nu mai
reprezint o soluie. Din acest motiv vom considera c elementele vectorului
reprezint o soluie, numai dac se afl n ordine strict cresctoare.
Acestea
reprezint
condiiile
de
continuare
ale
problemei.
3.
toate
#include <iostream.h>
// COMBINRI
const MAX=20;
int n,p,v[MAX] ;
int solutie(int k);
void afisare(int k);
void BK(int k);
void main()
{cout<<"n= ";cin>>n; cout<<"p= ";cin>>p;
BK(1);
}
void BK(int k)
{int i;
for (i=v[k-1]+1;i<=n;i++) //la pasul k selectm din mulime un element mai mare dect
elementul
{v[k]=i;
//de pe poziia k-1
if (solutie(k))
//nu este necesar s verificam condiiile de continuare, ele sunt
respectate afisare(k); //datorit modului n care am selectat elementele.
else
BK(k+1);
}
}
int solutie(int k)
{if (k==p) return 1;
return 0;}
void afisare(int k)
{int i;
for (i=1;i<=k;i++) cout<<v[i]<<" ";
cout<<endl;
}
4. SUBMULIMI
S se genereze toate submulimile mulimii S={1,2,3, ... ,n}.
Exemplu: pentru n=3, S={1,2,3}, submulimile sunt urmtoarele:
-mulimea vid, {1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}
S observm c pentru a obine toate submulimile unei mulimi, este suficient
n
elemente.
#include <iostream.h>
//
SUBMULIMI 1
const MAX=20;
int n,p,v[MAX] ;
int solutie(int k);
void afisare(int k);
void BK(int k);
void main()
{int i;
cout<<"n= ";cin>>n;
cout<<"mulimea vida"<<endl;
p
for(p=1;p<=n-1;p++)
//generm C n elemente
BK(1);
cout<<"{";
for(i=1;i<n;i++)
cout<<i<<", ";
cout<<n<<"}";
}
void BK(int k)
{int i;
for (i=v[k-1]+1;i<=n;i++)
{v[k]=i;
if (solutie(k))
afisare(k);
else
BK(k+1);
}
}
int solutie(int k)
{if (k==p)
return
1;
return 0;
}
void afisare(int k)
{ cout<<"{ ";
for (int i=1;i<k;i++) cout<<v[i]<<", ";
cout<<v[k]<<" }"<<endl;
}
#include <iostream.h>
const MAX=20;
int n,p,v[MAX] ;
int valid(int k);
int solutie(int k);
void afisare(int k);
void BK(int k);
//SUBMULIMI 2
void main()
{int i;
cout<<"n= ";cin>>n;
cout<<"mulimea vida"<<endl;
BK(1);
}
void BK(int k)
{int i;
for (i=v[k-1]+1;i<=n;i++)
{v[k]=i;
afisare(k);
BK(k+1);
}
}
D
D
D
D
2.
v[i]
linia i
linia k
v[k]
D
3. Obinem o soluie dac am reuit s plasm toate cele n dame, adic k=n.
v
1
k=1
v
1
v
1
k=2
1
k=2
k=2
1
3
pe linia 3 nu mai putem plasa nici o
dam, selectm alt valoare pe linia 2 v
k=2
1
4
v
1
v
1
D
D
k=3
4
k=3
4
2
-pe linia 4 nu putem plasa nici o dam
-pe linia 3 nici o alt coloan nu este
corect
-pe linia 2 nu mai exist nici o poziie
disponibil
-se revine la linia 1
v
2
k=1
v
2
v
2
v
k=2
1
k=2
D
D
2
k=2
2
v
2
v
2
3
k=2
4
D
k=3
v
2
v
2
v
2
k=4
D
k=4
k=4
D
D
D
Am obinut prima soluie !
#include <iostream.h>
#include <math.h>
#define MAX 20
//
DAME
int n,v[MAX],sol;
int valid(int k);
int solutie(int k);
void afisare();
void BK(int k);
void main()
{cout<<"n= ";cin>>n;
BK(1);
}
void BK(int k)
{int i;
for (i=1;i<=n;i++)
{v[k]=i;
if (valid(k)==1)
{if (solutie(k)==1)
sfisare();
else
BK(k+1);
}
}
}
int valid(int k)
{int i;
for (i=1;i<=k-1;i++)
if ((v[i]==v[k])||(abs(v[k]-v[i])==(k-i)))
return 0;
return 1;}
int solutie(int k)
{if (k==n)
return 1;
return 0;}
void afisare()
//afisam solutiile sub forma unei matrice
{int i,j,x;
sol++; cout<<"\n Solutia: "<<sol<<'\n';
for (i=1;i<=n;i++)
{for (j=1;j<=n;j++)
if (v[i]==j) cout<<"D ";
else
cout<<"_ ";
cout<<'\n';
}
}
7. Problema rucsacului
ntr-un rucsac se poate transporta o anumit greutate maxim G.
O persoan dispune de n obiecte. Pentru fiecare obiect se cunoare greutatea i
ctigul pe care persoana l poate obine transportnd acelst obiect.
Ce obiecte trebuie s transporte persoana respectiv pentru a obine un ctig
maxim.
Datele de intrare se citesc din fiierul RUCSAC.IN astfel:
- linia 1: n G -unde n este numrul de obiecte i G greutatea maxim admis
de rucsac
- linia i: nume[i] g[i] c[i]
unde:
Exemplu:
RUCSAC.IN
4 20
pantaloni 5 5
caciula 10 3
camasa 10 7
pantofi 5 2
Castigul maxim: 14
pantaloni 5 5
camasa 10 7
pantofi 5 2
cu soluia precedent, n cazul n care ctigul obinut este mai mare dect
precedentul vom reine aceast soluie. Vom considera ctigul iniial 0.
n-numrul de obiecte
G
nume[ ][ ]
g[ ]
c[ ]
v[ ]
-vectorul soluie:
0-obiectul nu este transportat,
1-obiectul este transportat
s_max
sol_max
#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#define MAX 20
int n,v[MAX],sol_max[MAX],g[MAX],c[MAX],s,s_max,G,gr,nr_sol;
char nume[MAX][MAX];
void back(int k);
int valid(int k);
void optim();
void citire();
void afisare();
main()
{citire();
back(1);
afisare();
//afisam solutia optima
}
void back(int k)
{ int i;
for(i=0;i<=1;i++)
{v[k]=i;
//0-obiectul k sete NEselectat, 1-obiectul k este selectat
if (valid(k))
if (k==n) optim();
//din multimea solutiilor vom retine doar solutia optima
else back(k+1); }
}
int valid(int k)
{ gr=0;
for(int j=1;j<=k;j++)
gr=gr+v[j]*g[j];
//-insumam greutatile obiectelor selectate pana la pasul k
if(gr<=G) return 1
//verificam daca greutatea cumulata nu depaseste greutatea maxima G
else return 0;
}
void optim()
{int s=0; nr_sol++;
for(int j=1;j<=n;j++)
s=s+v[j]*c[j];
//s-calculam suma ctigurilor obiectelor selectate
if((nr_sol==0)||(s>s_max))
//daca s>suma maxima, solutia este mai buna
{s_max=s;
//retinem solutia in sol_max
for(j=1;j<=n;j++)
sol_max[j]=v[j];
}
}
void citire()
{ ifstream f("RUCSAC.IN");
f>>n>>G;
//n-nr. obiecte, G-greutatea maxima
for (int i=1;i<=n;i++)
f>>nume[i]>>g[i]>>c[i];
//se citeste greutatea si ponderea fiecarui obiect
f.close();
}
void afisare()
{ nr_sol++;
cout<<"Castigul maxim:"<<s_max<<"\n";
for (int j=1;j<=n;j++)
if(sol_max[j]) cout<<nume[j]<<" "<<g[j]<<" "<<c[j]<<endl;
cout<<"\n";
}
3.Probleme si exercitii
Scrieti un program care afiseaza in fisierul cercuri.out toate
modalitatitile de inlocuire a literelor din imaginea alaturata cu cifre de
la 1 la 9 astfel incat suma cifrelor din fiecare cerc sa fie aceeasi.
REZOLVARE:
#include <fstream>
using namespace std;
ofstream fout("cercuri.out");
int X[11],P[10];
void afis()
{
for(int i=1;i<=9;i++)
fout<<X[i]<<" ";
fout<<endl;
}
int ok(int k)
{
if(k==9) if(X[8]+X[9]!=X[1]+X[2]) return 0;
else return 1;
if(k>3 && k%2==0)
if(X[k-2]+X[k-1]+X[k]!=X[1]+X[2]) return 0;
return 1;
}
void back(int k)
{
for(int i=1;i<=9;i++)
if(!P[i])
{
X[k]=i;
P[i]=1;
if(ok(k)) if(k==9) afis();
else back(k+1);
P[i]=0;
}
}
int main()
{
back(1);
return 0;
}
Exemplu:
hercule.in
66
345678
311119
5 6 7 12 11 10
1 7 1 13 1 1
1 8 1 14 15 16
1 9 10 11 12 17
hercule.out
11 4
100000
200000
345600
000700
0 0 0 8 9 10
0 0 0 0 0 11
100000
200000
345600
000700
000890
0 0 0 0 10 11
100000
200000
345600
000700
000800
0 0 0 9 10 11
100000
200000
340000
050000
060000
0 7 8 9 10 11
REZOLVARE:
#include <fstream>
using namespace std;
ifstream is("hercule.in");
ofstream os("hercule.out");
const int di[]={-1,0,1,0};
const int dj[]={0,1,0,-1};
int a[100][100], x[100][100], m,n,pmin=10000,nr=0;
void citire()
{
is>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
is>>a[i][j];
}
void afis(int x[100][100])
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
os<<x[i][j]<<" ";
os<<endl;
}
os<<endl;
}
void
alege(int
pas)//alege
minimul
si
numarul
de
drumuri
de
lungime minima
{
if(pas<pmin) { pmin=pas; nr=1;}
else if(pas==pmin) nr++;
}
void back(int i, int j, int pas)
{
x[i][j]=pas;
if(i==m && j==n) alege(pas);
else
for(int d=0;d<4;d++)
{
int inou=i+di[d];
int jnou=j+dj[d];
if(pas<a[inou][jnou] && x[inou][jnou]==0 && pas<pmin)
//inca nu e capcana, e pozitie noua si nu s-a depasit nr min de
pasi
back(inou,jnou,pas+1);
}
x[i][j]=0;
}
void backmin(int i, int j, int pas) //face doar drumurile de
lungime minima
{
x[i][j]=pas;
if(i==m && j==n && pas==pmin) afis(x);
else
for(int d=0;d<4;d++)
{
int inou=i+di[d];
int jnou=j+dj[d];
if(pas<a[inou][jnou] && x[inou][jnou]==0 && pas<pmin)
backmin(inou,jnou,pas+1);
}
x[i][j]=0;
}
int main()
{
citire();
back(1,1,1);
os<<pmin<<" "<<nr<<endl;
backmin(1,1,1);
is.close();
os.close();
return 0;
}
sau
#include <fstream>
using namespace std;
ifstream is("hercule.in");
ofstream os("hercule.out");
const int di[]={-1,0,1,0};
const int dj[]={0,1,0,-1};
int a[100][100], x[100][100], m,n,pmin=10000,nr=0;
void citire()
{
is>>m>>n;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
is>>a[i][j];
}
void afis(int x[100][100])
{
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
os<<x[i][j]<<" ";
os<<endl;
}
os<<endl;
}
void alege(int pas)
{
if(pas<pmin) { pmin=pas; nr=1;}
else if(pas==pmin) nr++;
}
void creste()
{
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
a[i][j]++;
}
void scade()
{
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
a[i][j]--;
}
void back(int i, int j, int pas)
{
scade();
x[i][j]=pas;
if(i==m && j==n) alege(pas);
else
for(int d=0;d<4;d++)
{
int inou=i+di[d];
int jnou=j+dj[d];
if(a[inou][jnou]>0 && x[inou][jnou]==0 && pas<pmin)
{
back(inou,jnou,pas+1);
}
}
x[i][j]=0;
creste();
}
void backmin(int i, int j, int pas) //face doar drumurile de
lungime minima
{
scade();
x[i][j]=pas;
if(i==m && j==n && pas==pmin) afis(x);
else
for(int d=0;d<4;d++)
{
int inou=i+di[d];
int jnou=j+dj[d];
if(a[inou][jnou]>0 && x[inou][jnou]==0 && pas<pmin)
{
backmin(inou,jnou,pas+1);
}
}
x[i][j]=0;
creste();
}
int main()
{
citire();
back(1,1,1);
os<<pmin<<" "<<nr<<endl;
backmin(1,1,1);
is.close();
os.close();
return 0;
}
void afis()
{
for(int i=1;i<=n;i++)
os<<x[i]<<" ";
os<<endl;
}
void back01(int k)
{
for(int i=0;i<=1;i++)
{
x[k]=i;
if(k>1) if(x[k]*x[k-1]!=1)
if(k==n) afis();
else back01(k+1);
else ;
else back01(k+1);
}
}
int main()
{
is>>n;
back01(1);
is.close();
os.close();
return 0;
}