diff --git a/dynamic-programming/notes.md b/dynamic-programming/notes.md index 857c51c3274b3e86dd398e15d5c649404fe93ad3..dd6cfdbaab3bc541e13a950a315d1c5d4503691e 100644 --- a/dynamic-programming/notes.md +++ b/dynamic-programming/notes.md @@ -36,8 +36,8 @@ so that every line is at most seven characters long, including spaces. The pena Example: The wrapping > x x x x -> xxxx -> xxxx +> xxxx +> xxxx has a total penalty of `(7 - 7)² + (7 - 4)² + (7 - 4)² = 0 + 9 + 9 = 18`. But there is a wrapping with a lower total penalty. @@ -50,35 +50,35 @@ Problem: Subject to an integer weight limit, what choice of items (allowing repe ## DAG * Edges (actions): - * … or - * … + * Take one of the items or + * Take one kg of nothing. * Vertices (situations): - * … + * How much weight have we put into the backpack? * Edge weights: - * … + * The value of the item being taken * Topological order: - * … + * 0 → 1 → … `weightLimit` * Goal: - * … + * Compute a longest path from 0 to `weightLimit` ## Backpointer Class * Information for the final result: - * … + * What item did we take? * Information to go back: - * … + * What was the weight of the item just taken? (redundant with the item taken) * Information to compare quality: - * … + * What is the *total* value of all of the items taken so far? ## Choosing a Backpointer * Exhaustive search: - * Generate …. - * Check that …. + * Generate items from the list or else 1 kg of nothing, but make sure that we don't try to go back to a negative total weight. + * Check that the item maximizes total value (the previous total value plus the value of the item used to go back). ## Example -* Item Z …. +* Item Z weighs 1 kg and is worth $0. * Item A weighs 3 kg and is worth $10. * Item B weighs 4 kg and is worth $14. @@ -87,20 +87,20 @@ Problem: Subject to an integer weight limit, what choice of items (allowing repe Weight (kg) Item Total Value (Back to Weight) ----------- ------ ----------- ---------------- 0 [none] $0 ⊥ - 1 Item … … … - 2 Item … … … - 3 Item … … … - 4 Item … … … - 5 Item … … … - 6 Item … … … - 7 Item … … … - 8 Item … … … - 9 Item … … … - 10 Item … … … + 1 Item Z 0 0 + 2 Item Z 0 1 + 3 Item A 10 0 + 4 Item B 14 0 + 5 Item Z 14 4 + 6 Item A 20 3 + 7 Item A 24 4 + 8 Item B 28 4 + 9 Item A 30 6 + 10 Item A 34 7 Reversed Path ---- - 10 ← (Item …) ← … + 10 ← (Item A) ← 7 ← (Item A) ← 4 ← (Item B) ← 0 -------------------------------------------------------------------------------- diff --git a/dynamic-programming/src/features/knapsack/solver.js b/dynamic-programming/src/features/knapsack/solver.js index 495b9e198445fb4ff055bf7ccd9c339b1b63a83f..ff780b5e39ca74a1f413a71705830c265adfd043 100644 --- a/dynamic-programming/src/features/knapsack/solver.js +++ b/dynamic-programming/src/features/knapsack/solver.js @@ -1,8 +1,9 @@ import { Item } from './items.js'; class Backpointer { - constructor() { - // TODO: stub + constructor(item, totalValue) { + this.item = item; + this.totalValue = totalValue; } } @@ -13,5 +14,13 @@ function chooseBackpointer(items, backpointers) { export function chooseItems(items, weightLimit) { console.assert(Number.isInteger(weightLimit), `Tried to choose items with a noninteger weight limit ${weightLimit}.`); - return []; // TODO: stub + const backpointers = [new Backpointer(undefined, 0)]; + while (backpointers.length <= weightLimit) { + backpointers.push(chooseBackpointer(items, backpointers)); + } + const reversedPath = []; + for (let weight = weightLimit; weight > 0; weight -= backpointers[weight].item.weight) { + reversedPath.push(…); + } + return reversedPath.reverse(); }