Transcript Greedy – metoda optimului local
Slide 1
?? ?
Greedy
Backtracking
?
Slide 2
Fie mulțimile 𝑆𝑖 , 𝑖 = 1, 𝑛, card(𝑆𝑖 ) = 𝑛𝑖 , ∃ o relație de ordine pe 𝑆𝑖
𝑆 = 𝑆1 × 𝑆2 × ⋯ × 𝑆𝑛 = 𝑥 = 𝑥1 , 𝑥2 , … , 𝑥𝑛 | 𝑥𝑖 ∈ 𝑆𝑖 spațiul soluțiilor
𝜑: 𝑆 → 𝑑𝑎, 𝑛𝑢
funcție de validare
𝑅 = 𝑥 ∈ 𝑆 | 𝜑 𝑥 = 𝑑𝑎
mulțimea soluțiilor rezultat
▪ 𝜑 𝑥 = 𝑑𝑎 ⟺ 𝑥 ∈ 𝑅
𝜑𝑘 : 𝑆1 × 𝑆2 × ⋯ × 𝑆𝑘 → 𝑑𝑎, 𝑛𝑢
funcții de validare parțială
▪ 𝜑𝑘−1 = 𝑑𝑎 ⇒ se poate adăuga un element 𝑥𝑘 ∈ 𝑆𝑘 cu 𝜑𝑘 = 𝑑𝑎.
Slide 3
Metodă rapidă, de complexitate redusă, pentru obținerea unei
soluții acceptabile (nu neapărat cea mai bună)
La fiecare pas se alege cea mai bună cale în contextul local,
ignorînd contextul general
Uneori soluția poate fi cea mai puțin dezirabilă
Este folosită atunci cînd găsirea celei mai bune soluții este prea
costisitoare
Slide 4
11
1, 3, 6, 2, 5, 9, 11 -> 124
15
5
2
22
32
1, 4, 8, 11
44
33
26
7
9
47
55
66
88
77
12
20
10
10
41
99
18
5
11
11
21
-> 45
Slide 5
Probleme rezolvate prin metoda Greedy
Problema poate fi imaginată ca o mulțime 𝐴 cu 𝑛 elemente
O soluție posibilă este o submulțime (𝐵 ⊆ 𝐴) care îndeplinește o
condiție dată (𝐵 este acceptabilă);
Pot exista mai multe submulțimi diferite acceptabile (soluții
posibile), dintre care una este considerată soluție optimă, pe
baza unui criteriu care trebuie maximizat (minimizat).
Slide 6
Operații (nu sînt întotdeauna evidente)
Alegerea unui element candidat 𝑥 din mulțimea 𝐴 (𝑥 ∈ 𝐴)
Verificarea acceptabilității elementului ales: adăugarea
elementului la soluția parțială construită o menține acceptabilă
sau o face inacceptabilă?
▪ 𝐵 ∪ {𝑥} este acceptabilă?
Adăugarea elementului ales la soluția parțială, dacă ea rămîne
acceptabilă.
▪ 𝐵 = 𝐵 ∪ {𝑥}
Slide 7
Algoritm general
Cum se alege un element candidat?
Cum se verifică
acceptabilitatea elementului
candidat?
se primește mulțimea 𝐴 cu 𝑛 elemente
se inițializează soluția 𝐵 ca mulțime vidă
repetă de (maxim) 𝑛 ori
▪ alege un element candidat 𝑥 din mulțimea 𝐴
▪ verifică dacă 𝐵 ∪ 𝑥 este soluție acceptabilă
▪ dacă da, adaugă 𝑥 la mulțimea 𝐵: 𝐵 = 𝐵 ∪ 𝑥
se trimite mulțimea 𝐵 ca soluție
Variantă:
prelucrare
inițială a mulțimii
A (sortare)
Slide 8
Exemple de probleme rezolvate prin algoritmi de tip Greedy:
Determinarea arborelui parțial de cost minim (soluția este întotdeauna optimă)
▪ Algoritmul lui Kruskal, algoritmul lui Prim
Problema rucsacului
▪ întreagă
▪ continuă
Interclasarea optimă a n vectori
Enunțuri
Suma maximă dintr-o
mulțimecomplete
de numere
Plata unei sume (cu bancnotă unitate)
Problema paznicului
Determinarea unui produs de transpoziții
Algoritmul Dijkstra
în manual
Slide 9
// I: capacitate totala (q), nr. obiecte (n), capacitate ocupata (c),
//
cistig (v)
// E: solutia x
void Rucsac_c(float q, int n, float* c, float* x)
{ float qr;
int i,j;
qr=q;
for(i=0; i0; i++)
if(qr>=c[i])
{ x[i]=1;
qr-=c[i];
//qr-=c[i]*x[i]
}
else
{ x[i]=qr/c[i];
qr=0;
//qr-=c[i]*x[i]
for(j=i+1;j x[j]=0;
}
}
Slide 10
Metodă lentă, costisitoare, complexitate mare
Verificarea (aproape) tuturor elementelor spațiului soluțiilor
𝑋 = 𝑥1 , 𝑥2 , … , 𝑥𝑛 , 𝑥𝑖 ∈ 𝑆𝑖 , 𝑖 = 1, 𝑛
𝜑 𝑥 = 𝑑𝑎
𝜑𝑘 - condiții de continuare
𝑋 se construiește element cu element
𝑥𝑖 primește o valoare din 𝑆𝑖 numai după toate elementele anterioare (𝑥1 , 𝑥2 , … , 𝑥𝑖−1 )
𝜑𝑖 𝑥1 , 𝑥2 , … , 𝑥𝑖 = 𝑑𝑎 ⇒ se trece la elementul 𝑖 + 1
▪ altfel se alege altă valoare pentru 𝑥𝑖
valoarea aleasă pentru 𝑥𝑖 e consumată ⇒ 𝐶𝑖 mulțimea valorilor consumate
▪ dacă nu mai sînt valori disponibile se revine la elementul anterior
𝜑𝑖 𝑥1 , 𝑥2 , … , 𝑥𝑖 = 𝑑𝑎 nu garantează obținerea unei soluții rezultat
Slide 11
Configurație curentă
Configurație inițială
Configurație soluție
Configurație finală
𝑣1
𝐶1
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
𝑥1
∅
𝑣1
𝐶1
𝑥1
𝑆1
… 𝑥𝑛
∅ ∅
… 𝑥𝑛
∅ ∅
… 𝑣𝑛
… 𝐶𝑛
… 𝑥𝑛
∅ ∅
Rezolvare problemă:
Configurație inițială → configurație soluție →…→configurație soluție → configurație finală
Slide 12
Atribuie și avansează
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
𝑥𝑖+1
∅
𝑣𝑖
𝑥𝑖+1
𝐶𝑖 ∪ 𝑣𝑖 ∅
𝑥𝑖
…
… 𝑣𝑖−1
===
… 𝐶𝑖−1 𝐶𝑖 ∪ 𝑣𝑖
…
𝑥𝑖+1
∅
Revenire
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
… 𝑣𝑖−1
…
… → … 𝐶𝑖−1
…
…
Încercare eșuată
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
𝑥𝑖+1
∅
𝑥𝑖+1
∅
…
… 𝑣𝑖−2 𝑥𝑖−1
… ← … 𝐶𝑖−2 𝐶𝑖−1
Revenire după construirea unei soluții
… 𝑣𝑛
… 𝐶𝑛
… 𝑣𝑛−1 𝑥𝑛
⋘ … 𝐶
𝑛−1 𝐶𝑛
𝑥𝑖
∅
…
…
…
…
Slide 13
inițializare 𝑺𝟏 , 𝑺𝟐 , … , 𝑺𝒏
𝑪𝒊 = ∅, 𝒊 = 𝟏, 𝒏
//construire configurație inițială
𝒊=𝟏
cît timp 𝒊 > 𝟎
//cît timp configurația nu e finală
dacă 𝒊 == 𝒏 + 𝟏
//configurație de tip soluție?
▪ reține soluția 𝑺𝒐𝒍 = 𝒙𝟏 , 𝒙𝟐 , … , 𝒙𝒏
▪ 𝒊=𝒊−𝟏
//revenire după construirea unei soluții
altfel
▪ dacă 𝑪𝒊 ≠ 𝑺𝒊
//mai sînt valori neconsumate
▪ alege o valoare 𝒗𝒊 ∈ 𝑺𝒊 − 𝑪𝒊
▪ 𝑪𝒊 = 𝑪𝒊 ∪ 𝒗𝒊
▪ dacă (𝒗𝟏 , 𝒗𝟐 , … , 𝒗𝒊−𝟏 , 𝒗𝒊 ) satisfac condițiile de continuare
𝒙𝒊 = 𝒗𝒊
//atribuie și avansează
𝒊= 𝒊+𝟏
▪ altfel
//revenire
▪ 𝑪𝒊 = ∅
▪ 𝒊=𝒊−𝟏
Slide 14
𝒊=𝟏
Particularități
ale
unor probleme
𝒙𝒊 =𝒂𝒊 −
𝒓𝒊
//primul
element minus rația, de multe ori 0=1-1
cît timp 𝒊 > 𝟎
𝒗𝒃 = 𝟎
//variabila
de impas
𝑆𝑖 - progresii aritmetice
cu valoarea
inițială 𝑎𝑖 , rația 𝑟𝑖 și valoarea finală 𝑠𝑖
cît timp 𝒙𝒊 < 𝒔𝒊 și 𝒗𝒃 == 𝟎
//alegerea unei noi valori pentru 𝒙𝒊
▪ uneori 𝑎𝑖 = 1, 𝑟𝑖 = 1
▪ 𝒙𝒊 = 𝒙𝒊 + 𝒓𝒊
//următorul termen în progresie
▪ posibil(𝒙𝒊 ,vb)
//sînt îndeplinite condițiile de continuare
toate
𝑆 = 1,2,
,𝑛
dacă 𝒗𝒃
== 𝑆
𝟎𝑖 sînt identice cu mulțimea
//impas
=>… revenire
▪ 𝒊=𝒊−𝟏
altfel
Avantaje
▪ dacă
== 𝒏 memorate explicit mulțimile 𝑺𝒊 și 𝑪𝒊
nu𝒊 trebuie
▪ dacă
condiții_finale(x)
soluție?
alegerea
unui element neconsumat//configurație
este ușoară
reține_soluția 𝑺𝒐𝒍 = 𝒙𝟏 , 𝒙𝟐 , … , 𝒙𝒏
▪ altfel
//avans
▪ 𝒊=𝒊+𝟏
▪ 𝒙𝒊 = 𝒂𝒊 − 𝒓𝒊
Slide 15
Metoda este de natură recursivă, deci ușor de implementat recursiv
Forma recursivă generală
backtracking(i)
dacă i==n+1
retine_solutia();
altfel
pentru fiecare element j din Si
x[i]=j;
daca posibil(i)
backtracking(i+1);
Slide 16
Exemple de probleme care se rezolvă prin metoda backtracking:
Problema celor 8 (n) regine.
Problema cavalerilor mesei rotunde.
Plata unei sume (cu/fără bancnotă unitate).
Generarea tuturor permutărilor.
Generarea tuturor Enunțuri
aranjamentelor.
complete în manual
Generarea tuturor combinărilor.
Problema colorării hărților.
Slide 17
D
𝑋 = 𝑥1 , 𝑥2 , … , 𝑥8
D
𝑥𝑖 - coloana pe care se află regina de pe linia i
D
𝑆𝑖 = 1, 2, 3, 4, 5, 6, 7, 8
𝑎𝑖 = 1, 𝑟𝑖 = 1, 𝑠𝑖 = 8
D
D
Condiție de continuare
D
Regina plasată, 𝑖
▪ nu e pe aceeași linie cu una plasată anterior
▪ implicit, nu e nevoie de verificare
▪ nu e pe aceeași coloană cu una plasată anterior
▪ 𝑥𝑖 ≠ 𝑥𝑗 pentru 𝑗 = 1, 𝑖 − 1
▪ nu e pe aceeași diagonală cu una plasată anterior
▪
𝑖 − 𝑗 ≠ 𝑥𝑖 − 𝑥𝑗 pentru 𝑗 = 1, 𝑖 − 1
Condiţie finală
nu e necesară
D
D
Slide 18
// Retine o configuratie (afisare)
// I: nr. solutie (nr), nr dame (n), vector solutie
// E: void retine_solutia(int nr, int n, int* x)
{ int i,j;
printf("\n Solutia numarul %d\n",nr);
for(i=1; i<=n; i++)
{ for(j=1; j<=n; j++)
printf("%c",j==x[i]?'D':'.');
printf("\n");
}
if(r=='n')
{ printf("\n\nUrmatoarea (n) sau Ultima (l)?");
r=_getch();
}
}
Slide 19
// Conditia de continuare
// I: solutia partiala (x), numarul de elemente (i)
// E: 1 daca e acceptabila, 0 daca nu e acceptabila
int posibil(int *x, int i)
{ int j, p;
p=1;
for( j=1; jif( x[i]==x[j] || abs(i-j)==abs(x[i]-x[j]) )
p=0;
return p;
}
Slide 20
// I: nr dame/dimensiune tabla (n) // E: nr solutii
int regine(int n)
{ int nr, *x, i, am;
x=new int[n+1];
//vectorul solutie
nr=0;
//numar solutii
i=1;
x[1]=0;
//prima valoare minus ratia
while(i>0)
//cit timp nu am ajuns la conf. finala
{ am=0;
while( x[i] { x[i]++;
//urmatoarea valoare pentru x[i]
am=posibil(x,i);
//este acceptabila?
}
if(!am) i--;
//impas, revenire
else
if( i==n )
//configuratie solutie
retine_solutia(++nr,n,x);
else
x[++i]=0;
//prima valoare minus ratia
}
delete x;
return nr;
}
Slide 21
// I: numar dame (n), element curent (i), vector solutie (x), numar
solutii (nr)
// E: numar solutii
int regine_r(int n, int i, int* x, int nr)
{ int j;
if( i==n+1)
retine_solutia(++nr,n,x);
else
for(j=1; j<=n; j++ )
{ x[i]=j;
if( posibil(x,i) )
nr=dame_r(n,i+1,x,nr);
}
return nr;
}
Slide 22
?? ?
Greedy
Backtracking
?
Slide 2
Fie mulțimile 𝑆𝑖 , 𝑖 = 1, 𝑛, card(𝑆𝑖 ) = 𝑛𝑖 , ∃ o relație de ordine pe 𝑆𝑖
𝑆 = 𝑆1 × 𝑆2 × ⋯ × 𝑆𝑛 = 𝑥 = 𝑥1 , 𝑥2 , … , 𝑥𝑛 | 𝑥𝑖 ∈ 𝑆𝑖 spațiul soluțiilor
𝜑: 𝑆 → 𝑑𝑎, 𝑛𝑢
funcție de validare
𝑅 = 𝑥 ∈ 𝑆 | 𝜑 𝑥 = 𝑑𝑎
mulțimea soluțiilor rezultat
▪ 𝜑 𝑥 = 𝑑𝑎 ⟺ 𝑥 ∈ 𝑅
𝜑𝑘 : 𝑆1 × 𝑆2 × ⋯ × 𝑆𝑘 → 𝑑𝑎, 𝑛𝑢
funcții de validare parțială
▪ 𝜑𝑘−1 = 𝑑𝑎 ⇒ se poate adăuga un element 𝑥𝑘 ∈ 𝑆𝑘 cu 𝜑𝑘 = 𝑑𝑎.
Slide 3
Metodă rapidă, de complexitate redusă, pentru obținerea unei
soluții acceptabile (nu neapărat cea mai bună)
La fiecare pas se alege cea mai bună cale în contextul local,
ignorînd contextul general
Uneori soluția poate fi cea mai puțin dezirabilă
Este folosită atunci cînd găsirea celei mai bune soluții este prea
costisitoare
Slide 4
11
1, 3, 6, 2, 5, 9, 11 -> 124
15
5
2
22
32
1, 4, 8, 11
44
33
26
7
9
47
55
66
88
77
12
20
10
10
41
99
18
5
11
11
21
-> 45
Slide 5
Probleme rezolvate prin metoda Greedy
Problema poate fi imaginată ca o mulțime 𝐴 cu 𝑛 elemente
O soluție posibilă este o submulțime (𝐵 ⊆ 𝐴) care îndeplinește o
condiție dată (𝐵 este acceptabilă);
Pot exista mai multe submulțimi diferite acceptabile (soluții
posibile), dintre care una este considerată soluție optimă, pe
baza unui criteriu care trebuie maximizat (minimizat).
Slide 6
Operații (nu sînt întotdeauna evidente)
Alegerea unui element candidat 𝑥 din mulțimea 𝐴 (𝑥 ∈ 𝐴)
Verificarea acceptabilității elementului ales: adăugarea
elementului la soluția parțială construită o menține acceptabilă
sau o face inacceptabilă?
▪ 𝐵 ∪ {𝑥} este acceptabilă?
Adăugarea elementului ales la soluția parțială, dacă ea rămîne
acceptabilă.
▪ 𝐵 = 𝐵 ∪ {𝑥}
Slide 7
Algoritm general
Cum se alege un element candidat?
Cum se verifică
acceptabilitatea elementului
candidat?
se primește mulțimea 𝐴 cu 𝑛 elemente
se inițializează soluția 𝐵 ca mulțime vidă
repetă de (maxim) 𝑛 ori
▪ alege un element candidat 𝑥 din mulțimea 𝐴
▪ verifică dacă 𝐵 ∪ 𝑥 este soluție acceptabilă
▪ dacă da, adaugă 𝑥 la mulțimea 𝐵: 𝐵 = 𝐵 ∪ 𝑥
se trimite mulțimea 𝐵 ca soluție
Variantă:
prelucrare
inițială a mulțimii
A (sortare)
Slide 8
Exemple de probleme rezolvate prin algoritmi de tip Greedy:
Determinarea arborelui parțial de cost minim (soluția este întotdeauna optimă)
▪ Algoritmul lui Kruskal, algoritmul lui Prim
Problema rucsacului
▪ întreagă
▪ continuă
Interclasarea optimă a n vectori
Enunțuri
Suma maximă dintr-o
mulțimecomplete
de numere
Plata unei sume (cu bancnotă unitate)
Problema paznicului
Determinarea unui produs de transpoziții
Algoritmul Dijkstra
în manual
Slide 9
// I: capacitate totala (q), nr. obiecte (n), capacitate ocupata (c),
//
cistig (v)
// E: solutia x
void Rucsac_c(float q, int n, float* c, float* x)
{ float qr;
int i,j;
qr=q;
for(i=0; i
if(qr>=c[i])
{ x[i]=1;
qr-=c[i];
//qr-=c[i]*x[i]
}
else
{ x[i]=qr/c[i];
qr=0;
//qr-=c[i]*x[i]
for(j=i+1;j
}
}
Slide 10
Metodă lentă, costisitoare, complexitate mare
Verificarea (aproape) tuturor elementelor spațiului soluțiilor
𝑋 = 𝑥1 , 𝑥2 , … , 𝑥𝑛 , 𝑥𝑖 ∈ 𝑆𝑖 , 𝑖 = 1, 𝑛
𝜑 𝑥 = 𝑑𝑎
𝜑𝑘 - condiții de continuare
𝑋 se construiește element cu element
𝑥𝑖 primește o valoare din 𝑆𝑖 numai după toate elementele anterioare (𝑥1 , 𝑥2 , … , 𝑥𝑖−1 )
𝜑𝑖 𝑥1 , 𝑥2 , … , 𝑥𝑖 = 𝑑𝑎 ⇒ se trece la elementul 𝑖 + 1
▪ altfel se alege altă valoare pentru 𝑥𝑖
valoarea aleasă pentru 𝑥𝑖 e consumată ⇒ 𝐶𝑖 mulțimea valorilor consumate
▪ dacă nu mai sînt valori disponibile se revine la elementul anterior
𝜑𝑖 𝑥1 , 𝑥2 , … , 𝑥𝑖 = 𝑑𝑎 nu garantează obținerea unei soluții rezultat
Slide 11
Configurație curentă
Configurație inițială
Configurație soluție
Configurație finală
𝑣1
𝐶1
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
𝑥1
∅
𝑣1
𝐶1
𝑥1
𝑆1
… 𝑥𝑛
∅ ∅
… 𝑥𝑛
∅ ∅
… 𝑣𝑛
… 𝐶𝑛
… 𝑥𝑛
∅ ∅
Rezolvare problemă:
Configurație inițială → configurație soluție →…→configurație soluție → configurație finală
Slide 12
Atribuie și avansează
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
𝑥𝑖+1
∅
𝑣𝑖
𝑥𝑖+1
𝐶𝑖 ∪ 𝑣𝑖 ∅
𝑥𝑖
…
… 𝑣𝑖−1
===
… 𝐶𝑖−1 𝐶𝑖 ∪ 𝑣𝑖
…
𝑥𝑖+1
∅
Revenire
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
… 𝑣𝑖−1
…
… → … 𝐶𝑖−1
…
…
Încercare eșuată
… 𝑣𝑖−1 𝑥𝑖
… 𝐶𝑖−1 𝐶𝑖
𝑥𝑖+1
∅
𝑥𝑖+1
∅
…
… 𝑣𝑖−2 𝑥𝑖−1
… ← … 𝐶𝑖−2 𝐶𝑖−1
Revenire după construirea unei soluții
… 𝑣𝑛
… 𝐶𝑛
… 𝑣𝑛−1 𝑥𝑛
⋘ … 𝐶
𝑛−1 𝐶𝑛
𝑥𝑖
∅
…
…
…
…
Slide 13
inițializare 𝑺𝟏 , 𝑺𝟐 , … , 𝑺𝒏
𝑪𝒊 = ∅, 𝒊 = 𝟏, 𝒏
//construire configurație inițială
𝒊=𝟏
cît timp 𝒊 > 𝟎
//cît timp configurația nu e finală
dacă 𝒊 == 𝒏 + 𝟏
//configurație de tip soluție?
▪ reține soluția 𝑺𝒐𝒍 = 𝒙𝟏 , 𝒙𝟐 , … , 𝒙𝒏
▪ 𝒊=𝒊−𝟏
//revenire după construirea unei soluții
altfel
▪ dacă 𝑪𝒊 ≠ 𝑺𝒊
//mai sînt valori neconsumate
▪ alege o valoare 𝒗𝒊 ∈ 𝑺𝒊 − 𝑪𝒊
▪ 𝑪𝒊 = 𝑪𝒊 ∪ 𝒗𝒊
▪ dacă (𝒗𝟏 , 𝒗𝟐 , … , 𝒗𝒊−𝟏 , 𝒗𝒊 ) satisfac condițiile de continuare
𝒙𝒊 = 𝒗𝒊
//atribuie și avansează
𝒊= 𝒊+𝟏
▪ altfel
//revenire
▪ 𝑪𝒊 = ∅
▪ 𝒊=𝒊−𝟏
Slide 14
𝒊=𝟏
Particularități
ale
unor probleme
𝒙𝒊 =𝒂𝒊 −
𝒓𝒊
//primul
element minus rația, de multe ori 0=1-1
cît timp 𝒊 > 𝟎
𝒗𝒃 = 𝟎
//variabila
de impas
𝑆𝑖 - progresii aritmetice
cu valoarea
inițială 𝑎𝑖 , rația 𝑟𝑖 și valoarea finală 𝑠𝑖
cît timp 𝒙𝒊 < 𝒔𝒊 și 𝒗𝒃 == 𝟎
//alegerea unei noi valori pentru 𝒙𝒊
▪ uneori 𝑎𝑖 = 1, 𝑟𝑖 = 1
▪ 𝒙𝒊 = 𝒙𝒊 + 𝒓𝒊
//următorul termen în progresie
▪ posibil(𝒙𝒊 ,vb)
//sînt îndeplinite condițiile de continuare
toate
𝑆 = 1,2,
,𝑛
dacă 𝒗𝒃
== 𝑆
𝟎𝑖 sînt identice cu mulțimea
//impas
=>… revenire
▪ 𝒊=𝒊−𝟏
altfel
Avantaje
▪ dacă
== 𝒏 memorate explicit mulțimile 𝑺𝒊 și 𝑪𝒊
nu𝒊 trebuie
▪ dacă
condiții_finale(x)
soluție?
alegerea
unui element neconsumat//configurație
este ușoară
reține_soluția 𝑺𝒐𝒍 = 𝒙𝟏 , 𝒙𝟐 , … , 𝒙𝒏
▪ altfel
//avans
▪ 𝒊=𝒊+𝟏
▪ 𝒙𝒊 = 𝒂𝒊 − 𝒓𝒊
Slide 15
Metoda este de natură recursivă, deci ușor de implementat recursiv
Forma recursivă generală
backtracking(i)
dacă i==n+1
retine_solutia();
altfel
pentru fiecare element j din Si
x[i]=j;
daca posibil(i)
backtracking(i+1);
Slide 16
Exemple de probleme care se rezolvă prin metoda backtracking:
Problema celor 8 (n) regine.
Problema cavalerilor mesei rotunde.
Plata unei sume (cu/fără bancnotă unitate).
Generarea tuturor permutărilor.
Generarea tuturor Enunțuri
aranjamentelor.
complete în manual
Generarea tuturor combinărilor.
Problema colorării hărților.
Slide 17
D
𝑋 = 𝑥1 , 𝑥2 , … , 𝑥8
D
𝑥𝑖 - coloana pe care se află regina de pe linia i
D
𝑆𝑖 = 1, 2, 3, 4, 5, 6, 7, 8
𝑎𝑖 = 1, 𝑟𝑖 = 1, 𝑠𝑖 = 8
D
D
Condiție de continuare
D
Regina plasată, 𝑖
▪ nu e pe aceeași linie cu una plasată anterior
▪ implicit, nu e nevoie de verificare
▪ nu e pe aceeași coloană cu una plasată anterior
▪ 𝑥𝑖 ≠ 𝑥𝑗 pentru 𝑗 = 1, 𝑖 − 1
▪ nu e pe aceeași diagonală cu una plasată anterior
▪
𝑖 − 𝑗 ≠ 𝑥𝑖 − 𝑥𝑗 pentru 𝑗 = 1, 𝑖 − 1
Condiţie finală
nu e necesară
D
D
Slide 18
// Retine o configuratie (afisare)
// I: nr. solutie (nr), nr dame (n), vector solutie
// E: void retine_solutia(int nr, int n, int* x)
{ int i,j;
printf("\n Solutia numarul %d\n",nr);
for(i=1; i<=n; i++)
{ for(j=1; j<=n; j++)
printf("%c",j==x[i]?'D':'.');
printf("\n");
}
if(r=='n')
{ printf("\n\nUrmatoarea (n) sau Ultima (l)?");
r=_getch();
}
}
Slide 19
// Conditia de continuare
// I: solutia partiala (x), numarul de elemente (i)
// E: 1 daca e acceptabila, 0 daca nu e acceptabila
int posibil(int *x, int i)
{ int j, p;
p=1;
for( j=1; jif( x[i]==x[j] || abs(i-j)==abs(x[i]-x[j]) )
p=0;
return p;
}
Slide 20
// I: nr dame/dimensiune tabla (n) // E: nr solutii
int regine(int n)
{ int nr, *x, i, am;
x=new int[n+1];
//vectorul solutie
nr=0;
//numar solutii
i=1;
x[1]=0;
//prima valoare minus ratia
while(i>0)
//cit timp nu am ajuns la conf. finala
{ am=0;
while( x[i]
//urmatoarea valoare pentru x[i]
am=posibil(x,i);
//este acceptabila?
}
if(!am) i--;
//impas, revenire
else
if( i==n )
//configuratie solutie
retine_solutia(++nr,n,x);
else
x[++i]=0;
//prima valoare minus ratia
}
delete x;
return nr;
}
Slide 21
// I: numar dame (n), element curent (i), vector solutie (x), numar
solutii (nr)
// E: numar solutii
int regine_r(int n, int i, int* x, int nr)
{ int j;
if( i==n+1)
retine_solutia(++nr,n,x);
else
for(j=1; j<=n; j++ )
{ x[i]=j;
if( posibil(x,i) )
nr=dame_r(n,i+1,x,nr);
}
return nr;
}
Slide 22