Sunteți pe pagina 1din 9

LABORATOR 1

METODA BRANCH AND BOUND (B&B)

Branch and bound este o paradigmă de proiectare a algoritmului


care este în general utilizată pentru rezolvarea problemelor de
optimizare combinatorie. Aceste probleme sunt de obicei exponențiale
în ceea ce privește complexitatea timpului și pot necesita explorarea
tuturor permutărilor posibile în cel mai rău caz. Tehnica Branch and
Bound Algorithm rezolvă aceste probleme relativ rapid.

Exemplu: Problema rucsacului 0/1

Să luăm în considerare problema rucsacului 0/1 pentru a


înțelege metoda B&B. Există mulți algoritmi prin care problema
rucsacului poate fi rezolvată:
1. Algoritm Greedy pentru Rucsac Fracțional;
2. Algoritm de programare dinamică (PD) pentru Rucsac 0/1;
3. Algoritm Backtracking pentru problema Rucsac 0/1.

Să vedem abordarea Branch and Bound pentru a rezolva


problema rucsacului 0/1: Soluția Backtracking poate fi optimizată dacă
cunoaștem un subarbore cu cea mai bună soluție posibilă înrădăcinată
cu fiecare nod. Dacă cel mai bun din subarborele este mai rău decât cel
mai bun actual, putem ignora pur și simplu acest nod și subarborii săi.
Deci, calculăm legătura (cea mai bună soluție) pentru fiecare nod și
comparăm legătura cu cea mai bună soluție curentă înainte de a
explora nodul.

Fie avem doi vectori întregi val [0 .. n-1] și wt [0 .. n-1] care


reprezintă valori și greutăți asociate respectiv cu n itemi. Aflați subsetul
valorii maxime ale val [] astfel încât suma greutăților acestui subset să
fie mai mică sau egală cu capacitatea de rucsac W.

1 din 9 Profesor A.D.


Să explorăm toate abordările pentru această problemă:
1. O abordare Greedy este de a alege articolele în ordinea
descrescătoare a valorii pe unitate de greutate. Abordarea
Greedy funcționează numai pentru problema rucsacului
fracționat și este posibil să nu producă rezultatul corect pentru
rucsacul 0/1.
2. Putem folosi programarea dinamică (PD) pentru problema
rucsacului 0/1. În PD, folosim un tablou bidimensional cu
dimensiunea n x W. Soluția PD nu funcționează dacă greutățile
articolelor nu sunt întregi.
3. Deoarece soluția PD nu funcționează întotdeauna, o soluție este
utilizarea Brute Force. Cu n itemi, există 2 n soluții care trebuie
generate, verificați fiecare pentru a vedea dacă satisfac
constrângerea, salvați soluția maximă care satisface
constrângerea. Această soluție poate fi exprimată ca arbore.

4. Putem folosi Backtracking pentru a optimiza soluția Brute Force.


În reprezentarea arborelui, putem face DFS al arborelui. Dacă
ajungem la un punct în care o soluție nu mai este fezabilă, nu
este nevoie să continuăm explorarea. În exemplul dat,
retrocedarea ar fi mult mai eficientă dacă am avea chiar mai
multe articole sau o capacitate mai mică a rucsacului.

2 din 9 Profesor A.D.


5. Am discutat diferite abordări pentru a rezolva problema de mai
sus și am văzut că soluția Branch și Bound este cea mai potrivită
metodă atunci când ponderile articolelor nu sunt întregi. Cum se
găsește legătura pentru fiecare nod pentru problema Rucsac 0/1?
Ideea este de a folosi abordarea Greedy, deoarece oferă
cea mai bună soluție pentru problema Rucsac Fracțional. Pentru
a verifica dacă un anumit nod ne poate oferi sau nu o soluție mai
bună, calculăm soluția optimă (prin nod) folosind abordarea
Greedy. Dacă soluția calculată de abordarea Greedy în sine este
mai mult decât cea mai bună de până acum, atunci nu putem
obține o soluție mai bună prin nod.

Algoritm complet

1. Sortați toate articolele în ordinea descrescătoare a raportului


valorii pe unitatea de greutate, astfel încât o limită superioară să
poată fi calculată utilizând Abordarea Greedy.
2. Inițializați profitul maxim, maxProfit = 0.
3. Creați o coadă goală, Q.
4. Creați un nod fictiv al arborelui decizional și puneți-l la Q.
Profitul și greutatea nodului fictiv sunt 0.
5. Urmăriți în timp ce Q nu este gol.

3 din 9 Profesor A.D.


a) Extrageți un articol din Q. Fie elementul extras să fie u.
b) Calculați profitul nodului de nivel următor. Dacă profitul este
mai mare decât maxProfit, atunci actualizați maxProfit.
c) Calculați legătura nodului de nivel următor. Dacă legat este mai
mult decât maxProfit, atunci adăugați nodul de nivel următor la
Q.
d) Luați în considerare cazul în care nodul de nivel următor nu este
considerat ca parte a soluției și adăugați un nod la coadă cu
nivelul ca următorul, dar greutatea și profitul fără a lua în
considerare nodurile de nivelul următor.

Prezentare ilustrativă a soluției

Date de intrare

Prima poziție din fiecare pereche este greutatea articolului și a doua


este valoarea articolului.
Articolele utilizate se vor păstra în vectorul obiecte:
obiecte [] = {{2, 40}; {3.14, 50}; {1.98, 100}; {5, 95}; {3, 30}};
Capacitatea rucsacului este: W = 10.

Date de ieșire

Profitul maxim posibil = 235

4 din 9 Profesor A.D.


1. Diagrama de mai sus prezintă ilustrația. Articolele sunt
considerate sortate după valoare / greutate.
2. Imaginea nu respectă cu strictețe algoritmul / codul, deoarece nu
există un nod fals în imagine.

Urmează implementarea C ++ a algoritmului de mai sus, pentru a


rezolva problema rucsacului folosind metoda B&B:

#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;

struct Item{
float weight;
int value;
};
struct Node{
int level, profit, bound;
float weight;
};
bool cmp(Item a, Item b){
double r1 = (double)a.value / a.weight;
double r2 = (double)b.value / b.weight;
return r1 > r2;
}
int bound(Node u, int n, int W, Item arr[]){
if (u.weight >= W) return 0;
int profit_bound = u.profit;
int j = u.level + 1;
int totweight = u.weight;
while ((j < n) && (totweight + arr[j].weight <= W)){
totweight += arr[j].weight;
profit_bound += arr[j].value;
j++;
}
if (j < n)
profit_bound += (W - totweight) * arr[j].value /
arr[j].weight;
return profit_bound;
}
int knapsack(int W, Item arr[], int n){
sort(arr, arr + n, cmp);
queue<Node> Q;
Node u, v;

5 din 9 Profesor A.D.


u.level = -1;
u.profit = u.weight = 0;
Q.push(u);
int maxProfit = 0;
while (!Q.empty()){
u = Q.front();
Q.pop();
if (u.level == -1) v.level = 0;
if (u.level == n-1) continue;
v.level = u.level + 1;
v.weight = u.weight + arr[v.level].weight;
v.profit = u.profit + arr[v.level].value;
if (v.weight <= W && v.profit > maxProfit)
maxProfit = v.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit) Q.push(v);
v.weight = u.weight;
v.profit = u.profit;
v.bound = bound(v, n, W, arr);
if (v.bound > maxProfit)
Q.push(v);
}
return maxProfit;
}
int main(){
int W = 10;
Item arr[] = {{2, 40}, {3.14, 50}, {1.98, 100}, {5, 95}, {3,
30}};
int n = sizeof(arr) / sizeof(arr[0]);
cout << "Profit maxim posibil = " << knapsack(W, arr, n);
return 0;
}

Soluția obținută în urma execuției codului C++ este:

Profit maxim posibil = 235

6 din 9 Profesor A.D.


SARCINA PENTRU LECȚIA DE LABORATOR

Problema: Puzzle

În această problemă se discută soluția a 8 puzzle-uri. Având o


placă 3×3 cu 8 plăci (fiecare placă are un număr de la 1 la 8) și un
spațiu gol. Obiectivul este de a plasa numerele pe dale pentru a se
potrivi configurației finale folosind spațiul gol. Putem a aluneca (a
mișca) se vor utiliza patru mișcări adiacente (stânga, dreapta, deasupra
și dedesubt) în spațiul gol. Pentru mai
multe detalii examinați desenul (în partea
stângă avem configurația inițială, iar în
dreapta avem configurația finală).

Căutarea unui nod de răspuns poate fi adesea accelerată


utilizând o funcție de clasare „inteligentă”, numită și funcție de cost
aproximativ, pentru a evita căutarea în subarbori care nu conțin un nod
de răspuns. Este similar cu tehnica de backtracking, dar folosește
căutarea de tip BFS.

În principiu, există trei tipuri de noduri implicate în Branch și Bound:


1) Nodul live este un nod care a fost generat, dar ai cărui copii nu
au fost încă generați.
2) E-nodul este un nod viu ai cărui copii sunt în prezent explorați.
Cu alte cuvinte, un nod E este un nod în curs de extindere.
3) Nodul mort este un nod generat care nu mai trebuie extins sau
explorat. Toți copiii unui nod mort au fost deja extinși.

Funcția de cost:
Fiecare nod X din arborele de căutare este asociat cu un cost. Funcția
de cost este utilă pentru determinarea următorului nod E. Următorul E-
nod este acela ce posedă cel mai mic cost. Funcția de cost este definită
ca: C (X) = g(X) + h(X), unde g(X) este costul atingerii nodului curent
din rădăcină, iar h(X) este costul atingerii unui nod de răspuns de la X.

7 din 9 Profesor A.D.


Funcția de cost ideală pentru algoritmul cu 8 puzzle-uri:
Presupunem că deplasarea unei țigle în orice direcție va avea un cost
unitar. Având în vedere acest lucru, definim o funcție de cost pentru
algoritmul cu 8 puzzle-uri după cum urmează: c (x) = f (x) + h (x), unde
f(x) este lungimea căii de la rădăcină la x (numărul de mișcări de până
acum) și h(x) este numărul de plăci (țigle) necompletate nu în poziția
lor de poartă (numărul de piese plasate greșit). Există cel puțin h(x)
mișcări pentru a transforma starea x într-o stare de obiectiv. Un
algoritm este disponibil pentru a obține o aproximare a h(x), care este o
valoare necunoscută.

Diagrama de mai jos arată calea urmată de algoritm pentru a ajunge la


configurația finală din configurația inițială dată de 8-Puzzle. Rețineți
că numai nodurile care au cea mai mică valoare a funcției cost sunt
extinse.

Sarcina:
Să se scrie un program C++ care va rezolva problema aceasta prin
metoda B&B.

8 din 9 Profesor A.D.


SARCINA PENTRU TEMA PENTRU ACASĂ

1) Problema de atribuire a postului

Fie avem N muncitori și N locuri de muncă. Orice lucrător poate fi


desemnat să îndeplinească orice loc de muncă, suportând anumite costuri
care pot varia în funcție de atribuirea lucrării. Este necesar să efectuați
toate lucrările prin atribuirea exactă a unui lucrător fiecărui loc de muncă
și exact un loc de muncă fiecărui agent în așa fel încât costul total al
misiunii să fie minimizat.

Date de intrare Date de ieșire


Lucrătorul A va avea jobul 1
Lucrătorul B va avea jobul 0
Lucrătorul C va avea jobul 2
Lucrătorul D va avea jobul 3

Costul optim este de 13

2) Problema N regine (șah)

Problema reginelor constă în plasarea a N-regine pe o tablă de șah de


dimensriunea N×N, astfel încât să nu se amenințe două regine. Astfel, o
soluție necesită ca două regine să nu aibă același rând, coloană sau
diagonală.

Date de intrare Date de ieșire


8 R 0 0 0 0 0 0 0
0 0 0 0 0 0 R 0
0 0 0 0 R 0 0 0
0 0 0 0 0 0 0 R
0 R 0 0 0 0 0 0
0 0 0 R 0 0 0 0
0 0 0 0 0 R 0 0
0 0 R 0 0 0 0 0

9 din 9 Profesor A.D.

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