Memra

Implementing & analyzing OilKnapsack

◈ 5 cards

The full bottom-up OilKnapsack DP with order reconstruction, then an empirical scaling experiment that confirms the O(nP) bound — the two graded report pieces.

From recurrence to code

Lesson 11.1 gave the model; now we implement it bottom-up and reconstruct which orders to fill — both are graded rubric lines ("construct a solution" and the report's results/screenshots), so neither can be skipped.

Step 3 (compute). Allocate a table of , set , then fill row by row using the recurrence. The sentinel marks unreachable sold-amounts; the "fill" branch is taken only when the order fits () and the smaller amount is reachable.

The objective. After the table is full, scan and take , remembering the winning b*.

Step 4 (reconstruct). From b*, walk : order was filled exactly when its row changed the value (); record it and drop by .

Worked example

Produce barrels, storage $s = \$2$ per unsold barrel. Orders $(q, p)(4, \$40), (6, \$50), (3, -\$5), (5, \$35)$. Order 3 has a negative price, so a correct DP must refuse it. The best plan fills orders 1 and 2: that sells exactly $4 + 6 = 10$ barrels for $\$40 + \$50 = \$90$, with zero unsold barrels and thus no storage — profit $\$90$. Any plan that touches the $-\$5$ order, or leaves barrels unsold to pay storage, does worse. The first exercise below computes and reconstructs exactly this.

Analyzing it experimentally

The project report asks for a running-time-vs-input-size chart. Wall-clock timing is machine-dependent and noisy, so for a reproducible demonstration we count the DP table cells computed — each cell is work, so the cell count is a faithful, deterministic stand-in for runtime. Hold fixed and double : an algorithm must double the work each time, and the normalized ratio must stay flat. The second exercise prints this table — that flat ratio with doubling counts is your empirical confirmation of the bound. (In your real report you would plot wall-clock seconds against for the screenshot; the shape is the same straight line.)

empty tablefull tableb*order listInitialisebest[0][0]=0, rest −∞Fill rowsi=1..n, b=0..PScan bmax best[n][b]−s(P−b)Trace backi=n..1 from b*Reportprofit + filled orders
The shape of the program. Nothing here is optional — the scan produces the graded profit and the traceback produces the graded order list.
best[i][b]b=0b=4b=6b=10i=0 (none)0−∞−∞−∞i=1 (4,$40)040−∞−∞i=2 (6,$50)0405090i=3 (3,−$5)0405090i=4 (5,$35)0405090Columns shown: the reachable b only.
The lesson’s own instance (P = 10, s = $2), restricted to the reachable sold-amounts — every other b is −∞. Accented cells are the traceback from b* = 10: rows 4 and 3 leave the value unchanged, so orders 4 and the −$5 order 3 were skipped; row 2 changes it (fill order 2, b → 4) and row 1 changes it again (fill order 1, b → 0). Profit = 90 − 2·0 = $90.
PhaseCostWhyfill tableΘ(nP)n(P+1) cells, O(1) eachstorage scanO(P)one pass over btracebackO(n)one row per ordertotalO(nP)the bound the project asksinput sizen + lg P bitsso nP is exponential in itO(nP) is pseudo-polynomial, not polynomial.
The exam trap in the last row: O(nP) looks polynomial because P looks like a count, but P is a *number* carried in about lg P bits, so nP is exponential in the length of the input. The bound is pseudo-polynomial.
NORMAL ~/memra/learn/comp-372/implementing-and-analyzing-oilknapsack utf-8 LF