Algoritmi. Tehnici si Limbaje de Programare



Yüklə 1,07 Mb.
səhifə10/13
tarix03.01.2018
ölçüsü1,07 Mb.
#36896
1   ...   5   6   7   8   9   10   11   12   13

METODA BACKTRACKING


La dispoziţia celor care rezolvă probleme cu ajutorul calculatorului există mai multe metode. Dintre acestea cel mai des utilizate sunt:

  • metoda Greedy;

  • metoda Divide et impera;

  • metoda Branch and Bound;

  • metoda Backtracking;

Metoda backtracking se aplică problemelor în care soluţia poate fi reprezentată sub forma unui vector – x = (x1, x2, x3, …xk,… xn) € S, unde S este mulţimea soluţiilor problemei şi S = S1 x S2 x… x Sn, şi Si sunt mulţimi finite având s elemente si xi € si , (¥)i = 1..n.

Pentru fiecare problemă se dau relaţii între componentele vectorului x, care sunt numite condiţii interne; soluţiile posibile care satisfac condiţiile interne se numesc soluţii rezultat. Metoda de generare a tuturor soluţiilor posibile si apoi de determinare a soluţiilor rezultat prin verificarea îndeplinirii condiţiilor interne necesită foarte mult timp.



Metoda backtracking evită această generare şi este mai eficientă. Elementele vectorului x, primesc pe rând valori în ordinea crescătoare a indicilor, x[k] va primi o valoare numai daca au fost atribuite valori elementelor x1.. x[k-1]. La atribuirea valorii lui x[k] se verifica îndeplinirea unor condiţii de continuare referitoare la x1…x[k-1]. Daca aceste condiţii nu sunt îndeplinite, la pasul k, acest lucru înseamnă ca orice valori i-am atribui lui x[k+1], x[k+1], .. x[n] nu se va ajunge la o soluţie rezultat.

Metoda backtracking construieşte un vector soluţie în mod progresiv începând cu prima componentă a vectorului şi mergând spre ultima cu eventuale reveniri asupra atribuirilor anterioare.

Metoda se aplica astfel :

1) se alege prima valoare sin S1 si I se atribuie lui x1 ;

2) se presupun generate elementele x1…x[k-1], cu valori din S1..S[k-1]; pentru generarea lui x[k] se alege primul element din S[k] disponibil si pentru valoarea aleasa se testează îndeplinirea condiţiilor de continuare.

Pot apărea următoarele situaţii :

a) x[k] îndeplineşte condiţiile de continuare. Daca s-a ajuns la soluţia finală (k = n) atunci se afişează soluţia obţinută. Daca nu s-a ajuns la soluţia finală se trece la generarea elementului următor – x [k-1];

b) x[k] nu îndeplineşte condiţiile de continuare. Se încearcă următoarea valoare disponibila din S[k]. Daca nu se găseşte nici o valoare în S[k] care să îndeplinească condiţiile de continuare, se revine la elementul x[k-1] şi se reia algoritmul pentru o nouă valoare a acestuia. Algoritmul se încheie când au fost luate in considerare toate elementele lui S1.

Problemele rezolvate prin această metodă necesită timp mare de execuţie, de aceea este indicat sa se folosească metoda numai daca nu avem alt algoritm de rezolvare.

Dacă mulţimile S1,S2,…Sn au acelaşi număr k de elemente, timpul necesar de execuţie al algoritmului este k la n. Dacă mulţimile S1, S2.. Sn nu au acelaşi număr de elemente, atunci se notează cu „m” minimul cardinalelor mulţimilor S1…Sn si cu „M”, maximul. Timpul de execuţie este situat în intervalul [m la n .. M la n]. Metoda backtracking are complexitatea exponenţială, in cele mai multe cazuri fiind ineficientă. Ea insa nu poate fi înlocuită cu alte variante de rezolvare mai rapide în situaţia în care se cere determinarea tuturor soluţiilor unei probleme.



Generarea permutărilor. Se citeşte un număr natural n. Să se genereze toate permutările mulţimii {1, 2, 3, …,n}.

Generarea permutărilor se va face ţinând cont că orice permutare va fi alcătuită din elemente distincte ale mulţimii A. Din acest motiv, la generarea unei permutări, vom urmări ca numerele să fie distincte.



Prezentăm algoritmul corespunzător cazului n=3:




















1




2




3







1




2




2




2




2

1




1




1




1




1




1










1




2




3













3




3




3




3










1

1




1




1




1




2




2




1




2




3
















1

1




1




1




2




3




3

2




2




2




2




2




2




  • se încarcă în stivă pe nivelul 1 valoarea 1;

  • încărcarea valorii 1 pe nivelul al 2-lea nu este posibilă, întrucât această valoare se găseşte şi pe nivelul 1 al stivei;

  • încărcarea valorii 2 pe nivelul al 2-lea este posibilă, deoarece această valoare nu mai este întâlnită;

  • valoarea 1 din nivelul al 3-lea se regăseşte pe nivelul 1;

  • valoarea 2 din nivelul al 3-lea se regăseşte pe nivelul al 2-lea;

  • valoarea 3 pe nivelul al 3-lea nu e întâlnită pe nivelurile anterioare; întrucât nivelul 3 este completat corect. Tipărim: 1 2 3

……

Algoritmul continuă până când stiva devine vidă.

Programul sursa este urmatorul:
Private Sub CommandButton14_Click()

cit_n "n = ", n

back_perm

End Sub
Sub back_perm()

Dim k As Integer

k = 1


While k > 0

Do

succesor am_suc, st, k



If am_suc = True Then

valid1 ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie(k) Then

tipar_r

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub valid1(ev As Boolean, st As stiva, k As Integer)

ev = True

For i = 1 To k - 1

If (st.ss(i) = st.ss(k)) Then

ev = False

End If

Next


End Sub
Sub tipar_r()

Dim i As Integer, b As String

b = " "

For i = 1 To n



b = b + Str$(st.ss(i)) + ","

Next


MsgBox b

End Sub
Sub succesor(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < n Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else


am_suc = False

End If


End Sub
Stiva este acea formă de organizare a datelor (structură de date) cu proprietatea că operaţiile de introducere şi scoatere a datelor se fac în vârful ei.­

Stivele se pot simula utilizând vectori.

Fie ST(i) un vector. ST(1), ST(2), ..., ST(n) pot reţine numai litere sau numai cifre. O variabilă K indică în permanentă vârful stivei.

Exemplificăm, în continuare, modul de lucru cu stiva:




În stiva iniţial vidă se introduce litera A, vârful stivei va fi la nivelul 1 (k-1);


introducem în stivă litera B, deci k va lua valoarea 2;


scoatem din stivă pe B (A nu poate fi scos);


scoatem din stivă pe A; stiva rămâne vidă

În mod practic la scoaterea unei variabile din stivă, scade cu 1 valoarea variabilei ce indică vârful stivei, iar atunci când scriem ceva în stivă, o eventuală valoare reziduală se pierde:

Pe un anumit nivel se retine, de regulă, o singură informaţie (literă sau cifră), însă este posibil; aşa cum va rezulta din exemplele, prezentate în lucrare, să avem mai multe informaţii, caz în care avem de a face cu stive duble, triple, etc.

Întreaga teorie a recursivităţii se bazează pe structura de tip stivă.



Prezentarea tehnicii Backtracking

Această tehnică se foloseşte în rezolvarea problemelor care îndeplinesc simultan următoarele condiţii:



  • soluţia lor poate fi pusă sub forma unui vector S=x1,x2, ...,xn, cu x1 € A1, x2 € A2 …, xn € An

  • mulţimile A1, A2 , …., An sunt mulţimi finite, iar elementele lor se consideră că se află într-o relaţie de ordine bine stabilită;

  • nu se dispune de o altă metodă de rezolvare, mai rapidă

  • x1 x2 …, xn pot fi la rândul lor vectori;

  • A1, A2 …, An pot coincide.

La întâlnirea unei astfel de probleme, dacă nu cunoaştem această tehnică, suntem tentaţi să generăm toate elementele produsului cartezian A1,A2 …,An si fiecare element să fie testat dacă este soluţie. Rezolvând problema în acest mod, timpul de execuţie este atât de mare, încât poate fi considerat infinit, algoritmul neavând nici o valoare practică.

De exemplu, dacă dorim să generăm toate permutările unei mulţimi finite A, nu are rost să generăm produsul cartezian AxAx.....xA, pentru ca apoi, să testăm, pentru fiecare element al acestuia, dacă este sau nu permutare (nu are rost să generăm 1.1,1.......1, pentru ca apoi să constatăm că nu am obţinut o permutare, când de la a doua cifră 1 ne puteam da seama că cifrele nu sunt distincte).

Tehnica Backtracking are la bază un principiu extrem de simplu:



  • se construieşte soluţia pas cu pas: x1, x2 …,xn

  • dacă se constată că, pentru o valoare aleasă, nu avem cum să ajungem la soluţie, se renunţă la acea valoare şi se reia căutarea din punctul în care am rămas.

Concret:

  • se alege primul element x, ce aparţine lui A;

  • presupunând generate elementele x1,x2 …,xk , aparţinând mulţimilor A1, A2 …,Ak, se alege (dacă există) xk+1, primul element disponibil din mulţimea Ak+1, apar două posibilităţi:

1) Nu s-a găsit un astfel de element, caz în care caz în care se reia căutarea considerând generate elementele x1,x2 …,xk+1 , iar aceasta se reia de la următorul element al mulţimii Ak rămas netestat;

2) A fost găsit, caz în care se testează dacă acesta îndeplineşte anumite condiţii de continuare apărând astfel două posibilităţi:



  • îndeplineşte, caz în care se testează dacă s-a ajuns la soluţie si apar din nou două posibilităţi:

- s-a ajuns la soluţie, se tipăreşte soluţia si se reia algoritmul considerând generate elementele x1,x2 …,xk, (se caută în continuare, un alt element al mulţimii Ak, rămas netestat);

- nu s-a ajuns la soluţie, caz în care se reia algoritmul considerând generate elementele x1,x2 …,xk , si se caută un prim element xk+2 € Ak.



  • nu le îndeplineşte caz în care se reia algoritmul considerând generate elementele x1,x2 …, xk , iar elementul xk-1 se caută între elementele mulţimii A, rămase netestate.

Algoritmii se termină atunci când nu există nici un element x1 € A1 netestat.

Observaţie: tehnica Backtracking are ca rezultat obţinerea tuturor soluţiilor problemei. În cazul în care se cere o sigură soluţie se poate forţa oprirea, atunci când a fost găsită.

Am arătat că orice soluţie se generează sub formă de vector. Vom considera că generarea soluţiilor se face intr-o stivă. Astfel, x1 € A1, se va găsi pe primul nivel al stivei, x2 € A2 se va găsi pe al doilea nivel al stivei,... xk € Ak se va găsi pe nivelul k al stivei. În acest fel, stiva (notată ST) va arăta astfel:




ST
Nivelul k+1 al stivei trebuie iniţializat (pentru a alege, în ordine, elementele mulţimii k+1 ). Iniţializarea trebuie făcută cu o valoare aflată (în relaţia de ordine considerată, pentru mulţimea Ak+1 ) înaintea tuturor valorilor posibile din mulţime. De exemplu, pentru generarea permutărilor mulţimii {1,2.....n}, orice nivel al stivei va lua valori de la 1 la n. Iniţializarea unui nivel (oarecare) se face cu valoarea 0. Procedura de iniţializare o vom numi INIT şi va avea doi parametri: k (nivelul care trebuie iniţializat si ST (stiva)).

Găsirea următorului element al mulţimii Ak (element care a fost netestat) se face cu ajutorul procedurii SUCCESOR (AS,ST,K). Parametrul AS (am succesor) este o variabilă booleană. În situaţia în care am găsit elementul, acesta este pus în stivă şi AS ia valoarea TRUE, contrar (nu a rămas un element netestat) AS ia valoarea FALSE..

Odată ales un element, trebuie văzut dacă acesta îndeplineşte condiţiile de continuare (altfel spus, dacă elementul este valid). Acest test se face cu ajutorul procedurii VALID (EV,ST,K).

Testul dacă s-a ajuns sau nu la soluţia finală se face cu ajutorul funcţiei SOLUTIE(k) iar o soluţie se tipăreşte cu ajutorul procedurii TIPAR. Prezentăm în continuare rutina Backtracking:
k:=1; CALL init(1,st);

while k>0

do

CALL succesor (as, st, k) ;



if as then CALLvalid(ev,st,k) then

loop until (not as) or (as and ev) ;

if as then

if solutie(k) then

CALL tipar

else


k:=k+l;

CALL init ( k, st );

end;

else


k:=k-1

wend
Observaţie: Problemele rezolvate prin această metodă necesită un timp îndelungat. Din acest motiv, este bine să utilizăm metoda numai atunci când nu avem la dispoziţie un alt algoritm mai eficient. Cu toate că există probleme pentru care nu se pot elabora alţi algoritmi mai eficienţi, tehnica backtracking trebuie aplicată numai în ultimă instanţă.

Fiind dată o tablă de şah, de dimensiune n, xn, se cer toate soluţiile de aranjare a n dame, astfel încât să nu se afle două dame pe aceeaşi linie, coloană sau diagonală (dame să nu se atace reciproc).
Exemplu: Presupunând că dispunem de o tablă de dimensiune 4x4, o soluţie ar fi următoarea:





D
















D

D
















D



Observăm că o damă trebuie să fie plasată singură pe linie. Plasăm prima damă pe linia 1, coloana 1.




D














































A doua damă nu poate fi aşezată decât în coloana 3.


D
















D




























Observăm că a treia damă nu poate fi plasată în linia 3. Încercăm atunci plasarea celei de-a doua dame în coloana 4.


D



















D

























A treia damă nu poate fi plasată decât în coloana 2.


D



















D




D



















În această situaţie dama a patra nu mai poate fi aşezată.

Încercând să avansăm cu dama a treia, observăm că nu este posibil să o plasăm nici în coloana 3, nici în coloana 4, deci o vom scoate de pe tablă. Dama a doua nu mai poate avansa, deci şi ea este scoasă de pe tablă. Avansăm cu prima damă în coloana 2.



D













































A doua damă nu poate fi aşezată decât în coloana 4.







D
















D

























Dama a treia se aşează în prima coloană.





D
















D

D






















Acum este posibil să plasăm a patra damă în coloana 3 si astfel am obţinut o soluţie a problemei.




D
















D

D
















D



Algoritmul continuă în acest mod până când trebuie scoasă de pe tablă prima damă.

Pentru reprezentarea unei soluţii putem folosi un vector cu n componente (având în vedere că pe fiecare linie se găseşte o singură damă).

Exemplu pentru soluţia găsită avem vectorul ST ce poate fi asimilat unei stive.

Două dame se găsesc pe aceeaşi diagonală dacă si numai dacă este îndeplinită condiţia: |st(i)-st(j)|=|i-j| ( diferenţa, în modul, între linii si coloane este aceeaşi).
În general ST(i)=k semnifică faptul că pe linia i dama ocupă poziţia k.



3

ST(4)

1

ST(3)

4

ST(2)

2

ST(1)


Exemplu: în tabla 4 x4 avem situaţia:





D
















D

D
















D




st(1)= 1 i = 1

st(3)= 3 j = 3

|st(1) - st(3)| = |1 – 3| = 2

|i – j| = |1 – 3| = 2
sau situaţia




D
















D

D
















D



st(1) = 3 i = 1

st(3) = 1 j = 3

|st(i) - st(j)| = |3 – 1| = 2

|i – j| = |1 – 3| = 2

Întrucât doua dame nu se pot găsi în aceeaşi coloană, rezultă că o soluţie este sub formă de permutare. O primă idee ne conduce la generarea tuturor permutărilor si la extragerea soluţiilor pentru problema ca două dame să nu fie plasate în aceeaşi diagonală. A proceda astfel, înseamnă că lucrăm conform strategiei backtracking. Aceasta presupune ca imediat ce am găsit două dame care se atacă, să reluăm căutarea.

Iată algoritmul, conform strategiei generate de backtracking:



  • În prima poziţie a stivei se încarcă valoarea 1, cu semnificaţia că în linia unu se aşează prima damă în coloană.

  • Linia 2 se încearcă aşezarea damei în coloana 1, acest lucru nefiind posibil întrucât avem doua dame pe aceeaşi coloană.

  • În linia 2 se încearcă aşezarea damei în coloana 2 , însă acest lucru nu este posibil, pentru că damele se găsesc pe aceiaşi diagonală (|st(1)-st(2)|=|1-2|);

  • Aşezarea damei 2 în coloana 3 este posibilă.

  • Nu se poate plasa dama 3 în coloana 1, întrucât în liniile 1-3 damele ocupa acelaşi coloană.

  • Şi această încercare eşuează întrucât damele de pe 2 şi 3 sunt pe aceeaşi diagonală.

  • Damele de pe 2-3 se găsesc pe aceeaşi coloană.

  • ­Damele de pe 2-3 se găsesc pe aceeaşi diagonală.

  • ­Am coborât în stivă mutând dama de pe linia 2 şi coloana 3 în coloana 4.

Algoritmul se încheie atunci când stiva este vidă. Semnificaţia procedurilor utilizate este următoarea:

INIT - nivelul k al stivei este iniţializat cu 0;

SUCCESOR - măreşte cu 1 valoarea aflată pe nivelul k al stivei în situaţia în care aceasta este mai mică decât n şi atribuie variabilei EV valoarea TRUE, în caz contrar, atribuie variabilei EV valoarea FALSE;

VALID - validează valoarea pusă pe nivelul k al stivei, verificând dacă nu avem două dame pe aceeaşi linie (st(k)=st(i)), sau dacă nu avem două dame pe aceeaşi diagonală (st(k)-st(i)=|k-i|)caz în care variabilei EV i se atribuie FALSE; în caz contrar, variabilei EV i se atribuie TRUE;

SOLUTIE - verifică dacă stiva a fost completată până la nivelul n inclusiv;

TIPAR - tipăreşte o soluţie.

Subprogramele prezentate in limbajul Visual Basic sunt descrise mai jos:


Global n As Integer, am_suc As Boolean, ev As Boolean

Type stiva

ss(100) As Integer

End Type


Global st As stiva
Sub init(k As Integer, st As stiva)

st.ss(k) = 0

End Sub
Sub succesor(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < n Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else

am_suc = False



End If

End Sub
Sub valid(ev As Boolean, st As stiva, k As Integer)

ev = True

For i = 1 To k - 1

If (st.ss(i) = st.ss(k)) Or (Abs(st.ss(i) - st.ss(k)) = Abs(k - i)) Then

ev = False

End If

Next


End Sub
Function solutie(k As Integer) As Integer

If k = n Then

solutie = True

Else


solutie = False

End If


End Function
Sub tipar()

Dim i As Integer, b As String

b = " "

For i = 1 To n



b = b + "(" + Str$(i) + "," + Str$(st.ss(i)) + "),"

Next


MsgBox b

End Sub
Sub back()

Dim k As Integer

k = 1


While k > 0

Do

succesor am_suc, st, k



If am_suc = True Then

valid ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie(k) Then

tipar

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub Button2_Click()

n = InputBox("n=", ib_title)

back


End Sub
Produsul cartezian a n mulţimi. Se dau mulţimile de mai jos şi se cere produsul cartezian al lor.

A1 = {1, 2, 3, …, k1}

A2 = {1, 2, 3, …, k2}

………………………

An = {1, 2, 3, …, kn}

Exemplu: A1 = {1, 2}

A2 = {1, 2, 3}

A3 = {1, 2, 3}

A1  A2  A3 = {(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 1), (1, 3, 2), (1, 3, 3), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 1), (2, 3, 2), (2, 3, 3)}.

Pentru rezolvare, se folosesc stiva ST şi un vector A ce reţine numerele k1, k2, …kn. Utilizăm metoda backtracking, uşor modificată din următoarele motive:



  1. Orice element aflat la nivelul k al stivei este valid, motiv pentru care procedura valid nu face altceva decât să atribuie variabilei ev valoarea TRUE.

  2. Limita superioară pe nivelul k al stivei este dată de A(k).

Modul de concepere a algoritmului rezultă din cele ce urmează:








1




2




3










1







1




1




1




2




2

1




1




1




1




1




1




2




3










1




2




3

2




2




3




3




3




3

1




1




1




1




1




1


Observaţii:

Algoritmul prezentat aici este de tip backtracking? Întrebarea are sens pentru că este absent mecanismul de întoarcere. Vom admite că şi aceasta este backtracking, dar „degenerat”.


Private Sub CommandButton16_Click()

Dim a As vector

cit_n "n=", n

cit_date "a", n, a

tipar " multimile sunt : ", n, a

back_prod_cart

End Sub
Sub cit_n(mes As String, nnn As Integer)

Do

nnn = InputBox(mes, y)



Loop Until n > 0 And n < 100

End Sub


Sub cit_date(mes As String, n As Integer, a As vector)

For i = 1 To n

a.v(i) = InputBox(mes + "(" + Str$(i) + ")=", y)

Next


End Sub
Sub tipar(mes As String, n As Integer, a As vector)

sir = ""


For i = 1 To n

sir = sir + Str$(a.v(i)) + ","

Next

MsgBox mes + " " + sir



End Sub
Sub back_prod_cart()

Dim k As Integer

k = 1

init k, st



While k > 0

Do

succesor_prod am_suc, st, k



If am_suc = True Then

valid_prod ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie(k) Then

tipar_r

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub valid_prod(ev As Boolean, st As stiva, k As Integer)

ev = True

End Sub


Function solutie(k As Integer) As Boolean

If k = n Then

solutie = True

Else


solutie = False

End If


End Function
Sub succesor_prod(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < a.v(k) Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else

am_suc = False



End If

End Sub


Sub init(k As Integer, st As stiva)

st.ss(k) = 0

End Sub
Generarea aranjamentelor. Se citesc n şi p. Să se genereze toate aranjamentele de n luate câte p.

Din analiza problemei rezultă următoarele:



  • stiva are înălţimea p;

  • fiecare nivel ia valori între 1 şi n;

  • elementele plasate pe diverse niveluri trebuie să fie distincte.

Algoritmul este asemănător cu cel de la permutări, cu deosebirea că aici stipa are înălţimea p.
Private Sub CommandButton17_Click()

cit_n "n = ", n

cit_n "p = ", p

back_aranj

End Sub
Sub back_aranj()

Dim k As Integer

k = 1

init k, st



While k > 0

Do

succesor am_suc, st, k



If am_suc = True Then

valid1 ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie1(k) Then

tipar_rr

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub valid1(ev As Boolean, st As stiva, k As Integer)

ev = True

For i = 1 To k - 1

If (st.ss(i) = st.ss(k)) Then

ev = False

End If

Next


End Sub
Sub tipar_rr()

Dim i As Integer, b As String

b = " "

For i = 1 To p



b = b + Str$(st.ss(i)) + ","

Next


MsgBox b

End Sub
Function solutie1(k As Integer) As Boolean

If k = p Then

solutie1 = True

Else

solutie1 = False



End If

End Function


Sub succesor(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < n Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else

am_suc = False



End If

End Sub


Sub init(k As Integer, st As stiva)

st.ss(k) = 0

End Sub
Generarea combinărilor. Se citesc n şi p numere naturale, np. Se cere să se genereze toate submulţimile cu p elemente ale mulţimii {1, 2, 3, …, n}.

Pentru rezolvarea problemei trebuie ţinut cont de următoarele:



  • stiva are înălţimea p;

  • elementele aflate pe niveluri diferite ale stivei trebuie să fie distincte;

  • pentru a evita repetiţia elementele se aşează în ordine crescătoare: pe nivelul k se va afla o valoare mai mare decât pe nivelul k-1 şi mai mică sau egală cu n-p+k.

Private Sub CommandButton18_Click()

cit_n "n = ", n

cit_n "p = ", p

back_comb

End Sub
Sub back_comb()

Dim k As Integer

k = 1


init k, st

While k > 0

Do

succesor_c am_suc, st, k



If am_suc = True Then

valid_c ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie1(k) Then

tipar_rr

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub succesor_c(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < n - p + k Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else


am_suc = False

End If


End Sub
Sub valid_c(ev As Boolean, st As stiva, k As Integer)

Dim i As Integer

ev = True

For i = 1 To k - 1

If (st.ss(i) = st.ss(k)) Then

ev = False

End If

Next


If k > 1 Then

If st.ss(k) < st.ss(k - 1) Then

ev = False

End If


End If

End Sub
Function solutie1(k As Integer) As Boolean

If k = p Then

solutie1 = True

Else

solutie1 = False



End If

End Function


Sub tipar_col()

Dim i As Integer, b As String

b = " "

For i = 1 To n



b = b + "Tara = " + Str$(i) + "; culoarea " + Str$(st.ss(i)) + " "

Next


MsgBox b

End Sub
Problema comis-voiajorului. Un comis voiajor trebuie să viziteze un număr n de oraşe. Iniţial, el se află într-unul dintre ele, notat 1. Comis – voiajorul doreşte să nu treacă de două ori prin acelaşi oraş, iar la întoarcere să revină în oraşul 1. Cunoscând legăturile existente între oraşe, se cere să se tipărească toate drumurile posibile pe care le poate efectua comis – voiajorul.




Exemplu: În figura alăturată sunt simbolizate cele 6 oraşe, precum şi drumurile existente între ele.








2




3





































1







4



















6




5









Comis - voiajorul are următoarele posibilităţi de parcurgere:

1, 2, 3, 4, 5, 6, 1;

1, 2, 5, 4, 3, 6, 1;

1, 6, 3, 4, 5, 2, 1;

1, 6, 5, 4, 3, 2, 1;

Legăturile existente între oraşe sunt date în matricea An,n. Elementele matricei A pot fi 0 sau 1 (matricea este binară).

1, dacă există drum între oraşele i şi j;

A(i,j) =

0 , altfel

Se observă că A(i,j) = A(j,i), oricare ar fi i,j {1, 2, 3, …, n} – matricea este simetrică.

Pentru rezolvarea problemei folosim stiva st. la baza stivei (nivelul 1) se încarcă numărul 1. Prezentăm în continuare modul de rezolvare a problemei.




2

De la oraşul 1 la oraşul 2 există drum, deci se va urca în stivă;

1




2

Oraşul 2 se mai găseşte în stivă, deci nu este acceptat;

2

1




3

De la oraşul 2 la oraşul 3 se găseşte drum; prin oraşul 3 nu s-a mai trecut, deci oraşul 3 este acceptat.

2

1

Algoritmul continuă în acest mod până se ajunge din nou la nivelul 1, caz în care algoritmul se încheie.

Un succesor, între 2 şi n, aflat pe nivelul k al stivei, este considerat valid dacă sunt îndeplinite următoarele condiţii:


  • nu s-a mai trecut prin oraşul simbolizat de succesor, deci acesta nu se regăseşte în stivă;

  • există drum între oraşul aflat la nivelul k-1 şi cel aflat la nivelul k;

  • dacă succesorul se găseşte la nivelul n, să existe drum de la el la oraşul 1.

Observaţii:

  1. Problemele rezolvate prin această metodă necesită un timp îndelungat de execuţie. Din acest motiv este bine să utilizăm metoda atunci numai atunci când nu mai avem la dispoziţie un alt algoritm mai eficient

  2. Menţionăm că nu există probleme pentru care nu se cunosc algoritmi eficienţi de rezolvare, deci backtracking este indicată.

  3. Rezolvarea iterativă încalcă principiul stivei atunci când verificăm condiţiile de continuare, sau atunci când tipărim soluţia găsită, pentru că accesăm orice nivel al stivei. Consider că o structură trebuie folosită ca atare atunci când este strict necesar. De exemplu, chiar şi segmentul de stivă al calculatorului poate fi accesat oriunde. Asta nu înseamnă că acolo nu se utilizează din plin „mecanismul” stivei.

Sub back_comis()

Dim k As Integer

k = 1


init k, st

While k > 0

Do

succesor_col am_suc, st, k



If am_suc = True Then

valid_col ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie(k) Then

tipar_col

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub succesor_comis(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < n Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else


am_suc = False

End If


End Sub

Sub valid_comis(ev As Boolean, st As stiva, k As Integer)

ev = True

For i = 1 To k - 1

If (st.ss(i) = st.ss(k)) And (mat.m(i, k) = 1) Then

ev = False

End If

Next


End Sub
Sub tipar_comis()

Dim i As Integer, b As String

b = " "

For i = 1 To n



b = b + "Tara = " + Str$(i) + "; vizitat " + Str$(st.ss(i)) + " "

Next


MsgBox b

End Sub
PROBLEMA COLORĂRII HĂRŢILOR


Enunţ:

Fiind dată o hartă cu n ţări, se cer toate soluţiile de colorare a hărţii, utilizând cel mult patru culori, astfel încât două ţări de frontieră comună să fie colorate diferit. Este demonstrat faptul că sunt suficiente numai patru culori pentru ca orice hartă să poată fi colorată.



Rezolvare:

Pentru exemplificare, vom considera următoarea hartă unde ţările sunt numerotate cu cifre cuprinse între 1 şi 5:




Figura 9.1 Harta ţărilor pentrproblema



O soluţie a acestei probleme este următoarea:

ţara 1 – culoarea 1

ţara 2 – culoarea 2

ţara 3 – culoarea 1

ţara 4 – culoarea 3

ţara 5 – culoarea 4

Harta este furnizată programului cu ajutorul unei matrice An,n

1, dacă ţara i se învecinează cu ţara j;

A(i,j) =

0 , altfel

Matricea A este simetrică. Pentru rezolvarea problemei se utilizează stiva st, unde nivelul k al stivei simbolizează ţara k, iar st[k] culoarea ataşată ţării k. Stiva are înălţimea n şi pe fiecare nivel ia valori între 1 şi 4.


Sub back_col()

Dim k As Integer

k = 1

init k, st



While k > 0

Do

succesor_col am_suc, st, k



If am_suc = True Then

valid_col ev, st, k

End If

Loop Until (Not am_suc) Or (am_suc And ev)



If am_suc Then

If solutie(k) Then

tipar_col

Else


k = k + 1

init k, st

End If

Else


k = k - 1

End If


Wend

End Sub
Sub succesor_col(am_suc As Boolean, st As stiva, k As Integer)

If st.ss(k) < 4 Then

am_suc = True

st.ss(k) = st.ss(k) + 1

Else


am_suc = False

End If


End Sub
Sub valid_col(ev As Boolean, st As stiva, k As Integer)

ev = True

For i = 1 To k - 1

If (st.ss(i) = st.ss(k)) And (mat.m(i, k) = 1) Then

ev = False

End If


Next

End Sub
Sub tipar_col()

Dim i As Integer, b As String

b = " "


For i = 1 To n

b = b + "Tara = " + Str$(i) + "; culoarea " + Str$(st.ss(i)) + " "

Next

MsgBox b


End Sub
Sub tipar_rr()

Dim i As Integer, b As String

b = " "

For i = 1 To p



b = b + Str$(st.ss(i)) + ","

Next


MsgBox b

End Sub


CAPITOLUL X

Yüklə 1,07 Mb.

Dostları ilə paylaş:
1   ...   5   6   7   8   9   10   11   12   13




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©muhaz.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin