diff --git a/dynamic-programming/notes.md b/dynamic-programming/notes.md
index 33d0f7d3739d7c68b972c6e4212aeb6fa7527d54..dc920f33b6b82cc1bdb0db4c20fd4f480daefdca 100644
--- a/dynamic-programming/notes.md
+++ b/dynamic-programming/notes.md
@@ -124,17 +124,17 @@ Problem: Wrap a paragraph to a line length, minimizing the sum of the squares of
 ## Backpointer Class
 
 *   Information for the final result:
-    *   …
+    *   What was the position of the previous linebreak?
 *   Information to go back:
-    *   …
+    *   What was the position of the previous linebreak?  (redundant with the info above) (alternatively, we could track the number of words on the chosen line)
 *   Information to compare quality:
-    *   …
+    *   What was the *total* penalty for the lines placed so far?
 
 ## Choosing a Backpointer
 
 *   Exhaustive search:
-    *   Generate ….
-    *   Check that ….
+    *   Generate start-of-line positions (in reverse order) as long as the character count does not exceed the line length and the start-of-line position does not go negative.
+    *   Check that the backpointer minimizes total penalty.
 
 ## Example
 
@@ -146,13 +146,17 @@ Problem: Wrap a paragraph to a line length, minimizing the sum of the squares of
      Index  Previous Index  Total Penalty
     ------  --------------  -------------
          0               ⊥              0
-         1               …              …
-         2               …              …
-         3               …              …
-         4               …              …
-         5               …              …
-         6               …              …
+         1               0             36
+         2               0             16
+         3               0              4
+         4               0              0
+         5               3              5
+         6               5             14
 
     Reversed Path
     ----
-    6 ← …
+    6 ← 5 ← 3 ← 0
+
+> x x x
+> x xxxx
+> xxxx
diff --git a/dynamic-programming/src/features/wrapping/solver.js b/dynamic-programming/src/features/wrapping/solver.js
index 062a7fa11ac32231da84d1930b7350c7e2707993..228810490384c2840dac67b5bfa5a067627cc09a 100644
--- a/dynamic-programming/src/features/wrapping/solver.js
+++ b/dynamic-programming/src/features/wrapping/solver.js
@@ -12,7 +12,17 @@ class Backpointer {
 function chooseBackpointer(wordLengths, lineLength, backpointers) {
   const index = backpointers.length;
   let best = new Backpointer(undefined, Infinity);
-  // TODO: stub
+  for (let start = index - 1, characterCount = wordLengths[start];
+    start >= 0 && characterCount < lineLength;
+    --start, characterCount += 1 + wordLengths[start]) {
+    const candidate = new Backpointer(
+      start,
+      backpointers[…].totalPenalty + penalty(…, …),
+    );
+    if (candidate.totalPenalty < best.totalPenalty) {
+      best = candidate;
+    }
+  }
   console.assert(
     best.previousIndex !== undefined,
     `One of the word lengths ${wordLengths} is too long to fit in a line of length ${lineLength}.`,