Sunteți pe pagina 1din 7

Produs cartezian pentru n multimi

Se dau n mulţimi, ca cele de mai jos: A1={1,2,3,...,k1},


A2={1,2,3,...,k2} .................... An={1,2,3,...,kn} Se cere să se genereze produsul lor
cartezian. Exemplu: pentru n=3 şi urmăroarele mulţimi A1={1,2} k1=2; A2={1,2,3}
k2=3; A3={1,2} k3=2 produsul cartezian este: A1xA2xA3 ={ (1,1,1), (1,1,2), (1,2,1),
(1,2,2), (1,3,1), (1,3,2), (2,2,1), (2,1,2), (2,2,1), (2,2,2), (2,3,1), (2,3,2)}
Prin urmare o soluţie este un şir de n elemente, fiecare element iAi, cu i=1,n.
Să analizăm exemplul de mai sus:
1. La pasul k selectăm un element din mulţimea Ak ={1,2,3,...,Kk}.
2. Elementele unei soluţii a produsului cartezian, pot să se repete, pot fi în orice ordine,
iar valori străine nu pot apare, deoarece le selectăm doar dintre elementele mulţimii Ak
. Prin urmare nu trebuie să impunem condiţii de continuare.
3. Obţinem o soluţie în momentul în care am completat n elemente în vectorul sol.

Vom memora numărul de elemente al fiecărei mulţimi Ak , într-un vector a.


Soluţiile le vom construi pe rând în vectorul sol.

#include<iostream>
#include<stdlib.h>
using namespace std;

int n,sol[10],a[10];

void init(int k)
{sol[k]=0;}

void tipar()
{int i;
for(i=1;i<=n;i++)
cout<<sol[i]<<" ";
cout<<endl;
}

int solutie(int k)
{return k==n+1;}

int succesor(int k)
{ if(sol[k]<a[k])
{sol[k]++;
return 1;
}
else return 0;
Metoda Backtracking

int valid(int k)
{return 1;
}

void back(int k)
{ if(solutie(k))tipar();
else{ init(k);
while(succesor(k))
if(valid(k))
back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
back(1);
return 0;
}

Generarea submulțimilor unei mulțimi.

Să se genereze toate submulţimile mulţimii S={1,2,3, ... ,n}.


Exemplu: pentru n=3, S={1,2,3}, submulţimile sunt următoarele:
Φ-mulţimea vidă, {1},{2},{3},{1,2},{1,3},{2,3},{1,2,3} .
Elementele unei submulțimi le vom păstra prin intermediul vectorului
caracteristic astfel: v[i] este 1, dacă iS și v[i] este 0 în caz contrar.
Astfel: {1} se memoreaza prin v=(1,0,0)
{1,3} se memorează prin v=(1,0,1), etc.
Să observăm că problema se reduce la generarea tuturor valorilor posibile pe
care le poate reține vectorul caracteristic. Nu sunt necesare condiții suplimentare
pentru validare.

#include<iostream>
using namespace std;

int n,sol[10];

void init(int k)
{sol[k]=-1;}

2
Metoda Backtracking

void tipar()
{int i;
for(i=1;i<=n;i++)
cout<<sol[i]<<" ";
cout<<endl;
}

int solutie(int k)
{return k==n+1;}

int succesor(int k)
{ if(sol[k]<1)
{sol[k]++;
return 1;
}
else return 0;
}

int valid(int k)
{return 1;
}

void back(int k)
{ if(solutie(k))tipar();
else{ init(k);
while(succesor(k))
if(valid(k))
back(k+1);
}
}
int main()
{
cout<<"n=";cin>>n;
back(1);
return 0;
}

Problema celor n dame.

Fiind dată o tablă de şah de dimensiune nxn, se cere să


se aranjeze cele n dame în toate modurile posibile pe tabla de

3
Metoda Backtracking

şah, astfel încât să nu se afle pe aceeaşi linie, coloană, sau diagonală (damele să nu se
atace). Exemplu pentru n=4 o soluţie este:

Observăm că o damă va fi plasată întotdeauna singură pe o linie. Acest lucru ne


permite să memorăm fiecare soluţie într-un vector v, considerând că o căsuță k a
vectorului reprezintă linia k iar conţinutul ei, adică sol[k] va conţine numărul coloanei
în care vom plasa regina. Pentru exemplul de
mai sus, vectorul sol va avea următorul
conţinut:

Să facem următoarele observaţii:


1. Pentru această problemă toate mulţimile Ak sunt identice, Ak={1,2,3,....,n} şi
reprezintă numărul coloanelor tablei de şah. Indicele k reprezintă numărul liniei tablei
de şah. Prin urmare, la pasul k selectăm un element din mulţimea Ak.
2. Condiţiile de continuare ale problemei :
a) Damele să nu fie pe aceeaşi linie - această condiţie este îndeplinită prin modul în
care am organizat memorarea datelor şi anume într-o căsuţă a vectorului putem trece
un singur număr de coloană.
b) Damele să nu fie pe aceeaşi coloană – adică
sol[k]≠sol[i], cu 1<=i<=k-1.
c) Damele să nu fie pe aceeaşi diagonală. Dacă două
dame se gasesc pe aceeaşi diagonală înseamnă că
cele două distanţe măsurate pe linie respectiv pe
coloană, dintre cele două dame sunt egale. Prin
urmare condiţia ca damele să nu fie pe aceeaşi
diagonală este: |sol[k]-sol[i]| ≠k-i , cu 1<=i<=k-1.
3. Obţinem o soluţie dacă am reuşit să plasăm toate
cele n dame, adică k=n.

Să urmărim modul în care se completează vectorul soluţie sol şi o reprezentare


grafică a ceea ce înseamnă valorile vectorului sol pe tabla de şah. Reprezentarea
descrie completarea vectorului până la obţinerea primei soluţii, pentru n=4. Algoritmul
de backtracking continuă în aceeaşi manieră, până la generarea tuturor soluţiilor.

4
Metoda Backtracking

5
Metoda Backtracking

#include<iostream>
#include<stdlib.h>
using namespace std;

int n,sol[10];

void init(int k)
{sol[k]=0;}

void tipar()
{int i;
for(i=1;i<=n;i++)
cout<<sol[i]<<" ";
cout<<endl;
}

int solutie(int k)
{return k==n+1;}

int succesor(int k)
{ if(sol[k]<n)
{sol[k]++;
return 1;
}
else return 0;
}

int valid(int k)
{int ev=1;
for(i=1;i<=k-1;i++)
if(sol[k]==sol[i] || abs(sol[k]-sol[i])==abs(k-i)) ev=0;
return ev;
}

void back(int k)
{ if(solutie(k))tipar();
else{ init(k);
while(succesor(k))
if(valid(k))
back(k+1);
}
}
int main()
{
6
Metoda Backtracking

cout<<"n=";cin>>n;
back(1);
return 0;
}

S-ar putea să vă placă și