0/1 Knapsack
Let an object be defined by a pair of numbers: {w, v}, where w represents the object's weight and v its value. Given a set of objects, defined by their {w, v} pairs, determine the maximum-value subset of these items such that the sum of the weights of this subset is smaller than or equal to Knapsack capacity W.
For this example, let W = 10, and let the set of objects {A, B, C, D, and E} be defined by:
{{2, 40}, {3.14, 50}, {1.98, 100}, {5, 95}, {3, 30}}
The General Branch and Bound Algorithm
- Each solution is assumed to be expressible as an array X[1:n]
(as was seen in Backtracking). - A predictor, called an approximate cost function CC, is assumed to have
been defined.
- Therefore, the criteria for the approximate cost function CC for minimization problems are:
- CC(X) <= C(X) for all live nodes X
- CC(X)=C(X) for all final leaves.
- The criteria for the approximate cost function CC for maximization problems are:
- CC(X) >= C(X) for all live nodes X
- CC(X)=C(X) for all final leaves.
- CC(X) >= C(X) for all live nodes X
- Definitions:
- A live node is a node that has not been expanded
- A dead node is a node that has been expanded
- The expanded node (or E-node for short)
is the live node with the best CC value.
- A live node is a node that has not been expanded
Procedure B&B() begin E: nodepointer; E := new(node); -- this is the root node which -- is the dummy start node H: heap; -- A heap for all the live nodes -- H is a min-heap for minimization problems, -- and a max-heap for maximization problems. while (true) do if (E is a final leaf) then -- E is an optimal solution print out the path from E to the root; return; endif Expand(E); if (H is empty) then report that there is no solution; return; endif E := delete-top(H); endwhile end
Procedure Expand(E) begin - Generate all the children of E; - Compute the approximate cost value CC of each child; - Insert each child into the heap H; end
Branch and bound steps for our example:
- The solution will be an array X[1:5] where each X[i] will indicate the inclusion or exclusion of a given object.
- As a predictor CC, we need an estimated cost that is >= than the real one. For this, we could use a naïve approach: Based on the one we would pick if we were using the Greedy Method and if fractional knapsack was allowed. In other words, the best ratio of value-per-unit-weight r=v/w
- To do so, we first sort the items by decreasing ratio of v/w: C(50.5 = 100/1.98), A(20 = 40/2), D(19 = 95/5), B(15.92 = 50/3.14), E(10 = 30/3), giving us the set array S: {C, A, D, B, E} with r values of {50.5, 20, 19, 15.92, 10}
- A solution X would represent an inclusion array in the order defined by S, so for X: {0,1,1,0,1} would indicate: C excluded, A included, D included, B excluded, E included (with a profit of 40+95+30 = 165)
- In terms of profit, if we were to choose in the order defined by S:{C, A, D, B, E}, the maximum possible profit (without the W limit) would be, sum(C to E) = 315; sum(A to E) = 215, sum(D to E) = 175; sum(B to E) = 80; sum(E) = 30
- Now, we use the following CC predictor:
CC(X at value k) = profit_so_far + fractional_knapsack_profiti=k+1 to nS[i]
Now, for the algorithm steps, we do the following:
- We first initialize the max-heap H with a dummy node E
- Since E is not a terminal node, we can expand it to include the first choices: C in (Xk=1:{1}) or C out, C (Xk=1:{0})
- The CC(Xk=1:{1}) = 0 + fractional_knapsack_profiti=1 to nS[i] = 251.24 :
- which accumulates as [ profit, total weight]:
- → add C → [100, 1.98] → add A → [140, 3.98] → add D → [235, 8.98] → add [1.02 units of B] →
- = [235, 8.98] → [235 + 1.02*15.92, 10] = [251.24, 10]
- The CC(Xk=1:{0}) = 0 + fractional_knapsack_profiti=2 to nS[i] = 182.76 :
- which accumulates as [ profit, total weight]:
- → don't add C → [0, 0] → add A → [40, 2] → add D → [135, 7] → add [3.0 units of B] →
- = [135, 7] → [135 + 3.0*15.92, 10] = [182.76, 10]
- We get the node from the max heap E (C in, or Xk=1:{1} ). Since the live node E is not a terminal node, we can expand it to include the next choices: A or A
- The CC(Xk=2:{1,1}) = 100 + fractional_knapsack_profiti=2 to nS[i] = 100 + 151.24 = 251.24 :
→ add A → [40, 3.98] → add D → [135, 8.98] → add [1.02 units of B] → [135 + 1.02*15.92, 10] = [151.24, 10] - The CC(Xk=2:{1,0}) = 100 + fractional_knapsack_profiti=3 to nS[i] = 100 + 143.08 = 243.08 :
→ don't add A → [0, 1.98] → add D → [95, 6.98] → add [3.02 units of B] → [95 + 3.02*15.92, 10] = [143.08, 10] - We get the node from the max heap E (Xk=2:{1,1}). Since the live node E is not a terminal node, we can expand it to include the next choices: D or D
- The CC(Xk=3:{1,1,1}) = 140 + fractional_knapsack_profiti=3 to nS[i] = 140 + 111.24 = 218.8 :
→ add D → [95, 8.98] → add [1.02 units of B] → [95 + 1.02*15.92, 10] = [111.24, 10] - The CC(Xk=3:{1,1,0}) = 140 + fractional_knapsack_profiti=4 to nS[i] = 140 + 78.8 = 178.8 :
→ don't add D → [0, 3.98] → add B → [50, 7.12] → add [2.88 units of E] → [50 + 2.88*10, 10] = [78.8, 10]