3.7.18 · D3Algorithm Paradigms

Worked examples — Branch and bound

3,692 words17 min readBack to topic

This page is the drill hall for Branch and Bound. The parent note taught what pruning is and why bounds must be optimistic. Here we hit every kind of situation B&B can throw at you — maximization, minimization, ties, zero-capacity edge cases, "nothing prunes" worst cases, a word problem, and an exam twist.

Before we start, a one-line reminder of the two golden rules (built fully in the parent):

Recall The prune rule in both directions

For maximization (e.g. 0-1 Knapsack): the bound is an upper bound (best possible value). Prune a node when . For minimization (e.g. Travelling Salesman Problem): the bound is a lower bound (least possible cost). Prune a node when . incumbent = value/cost of the best complete solution found so far.


The scenario matrix

Think of every B&B problem as a point in this grid. To not be surprised by an exam, you must have seen each row at least once.

Cell What makes it distinct Covered by
A. Max problem, pruning happens upper bound, incumbent beats a subtree Example 1
B. Min problem, pruning happens lower bound, forced/forbidden edges Example 2
C. Zero / degenerate input capacity , empty item set, single city Example 3
D. Tie in bounds two nodes share the same bound — tie-break rule Example 4
E. Worst case, nothing prunes bound never beats incumbent early → full tree Example 5
F. Item bigger than capacity an item can never fit; must be forced out Example 6
G. Real-world word problem translate English → objective + constraints Example 7
H. Exam twist: wrong-direction bound spot why a "clever" bound is invalid Example 8

Each example is tagged with its cell. Together they fill the whole grid.


Example 1 — Cell A: maximization with real pruning

Step 1 — Root bound (the optimistic estimate). Fill fractionally in density order: A full , B full , then C wants weight 10 but only is left, so take fraction . Why this step? The fractional fill (from the greedy relaxation) is a valid upper bound — allowing fractions only ever helps, so no integer solution can beat 85.

Step 2 — Branch on A (highest density first). Recall = decided profit, = decided weight (defined at the top of the page).

  • Include A : bound .
  • Exclude A : B full , then C fraction : bound .

Why this step? We split into two smaller subproblems ("A is in" / "A is out"). Least-Cost B&B will chase the higher bound first (85).

Step 3 — Expand include-A, then include-B. . Remaining capacity . C is next but weight 10 doesn't fit as a whole → its integer completion adds nothing. So the complete feasible solution {A,B} has value . Set incumbent . Why this step? A complete feasible solution is the first real number B&B can trust — until now every "bound" was only an optimistic guess. Recording it as the incumbent gives us the yardstick ("beat 70 or die") that all future pruning is measured against; without a stored incumbent there is nothing to compare bounds to.

Step 4 — Prune. The exclude-A node has bound . Since , prune it — the entire exclude-A subtree vanishes in one comparison. Also check {A,C}: weight , infeasible. {A,B,D}: weight , infeasible.

Verify: Brute-force the feasible sets under : {A}=40, {A,B}=70 (w7), {A,D}=50 (w7), {B}=30, {B,D}=40 (w10), {C}=50, {D}=10. Max . ✔ Matches, and yes the exclude-A branch was pruned.

Figure — Branch and bound

Example 2 — Cell B: minimization, forcing an edge raises the bound

Step 1 — Root lower bound (2-min rule). Each city touches exactly 2 tour edges, so it contributes at least its two cheapest incident edges. Sum, then halve (each edge counted by both endpoints).

  • City 1: cheapest two of
  • City 2: cheapest two of
  • City 3: cheapest two of
  • City 4: cheapest two of

Why this step? This is an under-estimate of any real tour, so it's a safe lower bound for a min problem — the mirror image of the knapsack upper bound.

Step 2 — Force edge into the tour. Now city 1 must use edge as one of its two edges. Its cheapest allowed pair becomes (still and here). City 2 must use too; cheapest pair . Cities 3, 4 unchanged. Why this step? Fixing an edge in a branch changes the constraints each endpoint city must satisfy, so its "two cheapest allowed edges" may change — we must recompute the bound to keep it valid for this restricted subproblem. Here it stayed equal only because was already each endpoint's cheapest edge, so no city was forced to give up a cheaper option.

Step 3 — Force a worse edge to see the rise. Force () instead. City 1 must use ; cheapest allowed pair (must include the forced 4, plus next cheapest 1). City 3 must use ; cheapest allowed pair . The bound rose from to : forcing a non-cheapest edge removes freedom, so the optimistic estimate can only go up.

Verify: The three distinct tours of 4 cities (fix start at 1):

Optimal . Both bounds (, ) are ✔ (valid under-estimates). ✔

Figure — Branch and bound

Example 3 — Cell C: degenerate input (zero capacity)

Step 1 — Root bound. Remaining capacity is , so nothing fits, not even a fraction: . Why this step? The fractional fill loop has zero capacity to give away, so it adds nothing.

Step 2 — The only complete solution. The empty set with value is feasible. incumbent .

Step 3 — Prune everything. Every child bound is → all pruned. No branching happens.

Verify: Max value with is (empty set is the only feasible set). ✔ Degenerate case handled: answer , tree = just the root.


Example 4 — Cell D: two nodes tie on the bound

Step 1 — State the tie. The live set (a priority queue that always hands back the node with the best bound) holds two nodes with the same key . The queue's ordering only ranks by bound; when bounds are equal it does not, by itself, say which to take — so an implementation must supply a tie-break rule as an extra ordering criterion. Why this step? We must first notice that the priority queue is under-specified at a tie, because that is the exact gap where two correct-but-different implementations diverge — pinning down the gap is what lets us reason about whether it can affect the answer.

Step 2 — Choose a tie-break, and say why. A common, practical choice is deeper node first (the node with more decisions already fixed). Why this rule and not another? A deeper node is closer to a complete solution, so expanding it tends to produce an incumbent sooner; an earlier incumbent means earlier pruning of the other tied node's siblings, i.e. less total work. This is a heuristic for speed only — it is not mandated by B&B. Other valid choices (insertion order / "oldest first", or lowest node-id) are equally correct; they just may explore more nodes.

Step 3 — Show correctness is order-independent. Whatever tie-break we use, B&B only ever prunes provably-hopeless nodes (). It never discards a node that could hold a strictly better solution. So the returned optimal value is identical for any tie-break — only the amount of work changes.

Verify: From Example 1 the optimum is regardless of expansion order. A tie changes speed, not the answer . ✔


Example 5 — Cell E: the worst case, nothing prunes

Step 1 — Compute the bounds numerically at each level. All items have density , and total weight , so the fractional fill always takes everything remaining. (Recall from the top: profit, weight, remaining capacity.)

  • Root : fill A,B,C fully . .
  • Include-A : add B,C fully . .
  • Exclude-A : the remaining items are just B,C, whose fractional fill is , so .
  • Include-A-Include-B : add C fully . .
  • Include-A-Exclude-B : add C fully . .

The first complete leaf gives incumbent .

Step 2 — Why the equal-value case blocks all pruning (reconciling the prune rule). The golden rule prunes a max-node when — ties do prune. So why isn't everything cut here? Because B&B records the incumbent as the best complete solution found so far, and updates it only on a strict improvement. Watch the order carefully:

  • The very first complete leaf B&B reaches has value ; at that moment incumbent was , so it becomes .
  • Every other full branch here also completes with value exactly . When B&B is about to record one of them, is not a strict improvement over incumbent , so the incumbent (and hence the returned solution) doesn't change — but B&B still had to walk down that branch to discover the leaf value before it could compare.

The subtlety: pruning by happens at an interior node before expanding it. But here every interior node's bound is or , and the incumbent only becomes after the first full leaf. Interior nodes with bound satisfy and would be pruned — once the incumbent is . The trap is that reaching that first -valued leaf already forces B&B to descend one full root-to-leaf spine, and along the way it enters interior nodes whose bound is not yet dominated (incumbent still ). So the first spine is fully explored no matter what, and equal-density flatness means every leaf value merely ties — never strictly beating to sharpen the incumbent further.

Net effect: essentially the whole tree gets touched. In the strict worst case (bounds never exceed any not-yet-found leaf value early), B&B examines all leaves.

Step 3 — Count leaves and state the optimum. With independent binary choices, the tree has leaves, and the optimum (all three fit) is . Why this happens? Flat, equal-density instances give no gap between the optimistic bound and real completions, so early strict domination never occurs. This is exactly the worst case the parent warned about: B&B stays (see Big-O Notation).

Verify: subsets; optimum value with is . ✔ Worst-case leaf count . ✔


Example 6 — Cell F: an item bigger than the whole knapsack

Step 1 — Handle B in the bound. When computing the fractional root bound, B can be partially taken (fractions allowed in the relaxation). Order A,B,C: A full , B: capacity left , take fraction . Bound . Why this step? The relaxation ignores the integrality constraint, so a too-heavy item may still contribute fractionally to the (optimistic) bound — that's fine, it only over-estimates.

Step 2 — But never branch into including B fully. The "include B" child sets infeasible. We give it bound — recall from the definition at the top of the page that just means "the worst possible score for a maximization node," so it is instantly any incumbent and pruned (equivalently, we simply never create the node). Only "exclude B" survives. Why this step? Feasibility (from Backtracking) kills the include-B node before any cost bound is even needed.

Step 3 — Finish. Feasible sets under : {A}=60(w3), {C}=20(w2), {A,C}=80(w5), {B} infeasible, {}=0. Best .

Verify: Brute force : {A}=60, {C}=20, {A,C}=80 (w5≤6), any set with B has w≥7>6 → infeasible. Max . ✔ The bound over-estimates (valid), and B is only used fractionally. ✔


Example 7 — Cell G: real-world word problem

Step 1 — Translate to knapsack. Objective: maximise total profit; constraint: total weight . Densities ₹/kg: P1, P2, P3, P4 → order P1, P2, P4, P3. Why this step? B&B needs an optimization frame — an objective to maximise and a hard constraint. Naming "profit" as the objective and " kg" as the constraint turns the English into the exact 0-1 Knapsack shape we already know how to bound.

Step 2 — Root bound. P1 full , P2 full , P4: capacity left , weight 4, take fraction . Bound .

Step 3 — Branch & prune. Include P1, include P2 . Remaining : P4 (w4) doesn't fit whole; P3 (w3) doesn't fit. Complete → incumbent . Try include P1, exclude P2, include P4 : complete → incumbent . Now any node with bound prunes. The naive "grab P4 first" () or "highest per-kg only" are both beaten.

Step 4 — Confirm optimum. : weight , profit .

Verify (units check): weight ✔; profit in ₹. Brute force all feasible sets (): best is . ✔ Greedy-by-density alone would have stopped at — B&B beats it.


Example 8 — Cell H: exam twist, spot the invalid bound

Step 1 — Recall the requirement. For maximization, the bound must be a guaranteed upper bound: every integer completion of the node. (Parent: "the bound must be a valid over-estimate.") Why this step? The whole proof of correctness rests on "even the best case here can't beat what I have." That proof is only valid if the bound truly is every completion — so we must state that requirement before testing any candidate bound against it.

Step 2 — Test it on Example 1. The true best completion of the root is the real optimum . A correct upper bound must be . The honest fractional bound is ; scaling gives — still here, but that safety is accidental, not guaranteed.

Step 3 — Break it deliberately. Take a node whose honest fractional bound equals its integer optimum (a "tight" node — e.g. every item fits with no leftover, as in Example 5 where the honest bound equals the optimum ). Then honest bound optimum . The scaled bound is . If the incumbent equals (found first in a tied branch), the rule prunes this node because discarding the branch that actually contains the true optimum.

Step 4 — Verdict. is invalid: scaling an upper bound down can push it below a real completion, so "even the best case is bad" is no longer a proof — it can lie. The lesson: aggressive pruning is allowed only with a provably optimistic bound. A tighter bound must come from a tighter relaxation, never from arbitrarily shrinking a valid one.

Verify: With (Example 5, all fit), honest bound optimum; scaled bound . A branch holding the optimum is pruned when incumbent arrives from a tied branch → optimum lost. So the rule is unsafe. ✔ (This mirrors the parent's first "common mistake.")


Recall Self-test

For a max problem, prune when? ::: For a min problem, prune when? ::: Does a tie in bounds change the returned optimum? ::: No — only the work done. When does B&B stay ? ::: When bounds never strictly beat the incumbent early (flat / equal-density instances). Can an item heavier than still affect the bound? ::: Yes, fractionally in the relaxation — but its "include" node is infeasible ( bound). Why can't you scale an upper bound down to prune more? ::: It may drop below a real completion and discard the true optimum.

See also: Dynamic Programming (exact but table-based, no pruning), A* Search (B&B's cousin: bound = with an admissible heuristic = optimistic), Hinglish version.