Algorithms Ā· Optimization

Dynamic programming and Matrix Chain Order

Dynamic programming solves each subproblem once and stores the result. Matrix Chain Order makes the method especially visible: the optimal cost emerges by filling two triangular tables one diagonal at a time.

When a problem fits dynamic programming

Splitting a problem is not enough. Dynamic programming helps when many recursive paths ask for the same subproblems and a globally optimal solution can be assembled from optimal smaller solutions.

Optimal substructure

An optimal choice contains optimal choices for the subproblems it creates.

Overlapping subproblems

Naive recursion recomputes the same states. Storing them removes that repetition.

State and choice

Define exactly what a cell represents and which decision reduces it to smaller states.

It is not one algorithm. It is a design method: define states, a recurrence, base cases, evaluation order and, when needed, how to reconstruct the choices.

Two ways to evaluate the same states

Top-down

Memoization

Start from the full problem, recurse and cache each result on first visit. Only requested states are evaluated.

Bottom-up

Tabulation

Start from base cases and fill a table in an order that makes every dependency available. MatrixChainOrder uses this approach.

The problem: where should parentheses go?

Matrix multiplication is associative, so every parenthesization produces the same final matrix. The number of scalar multiplications can change dramatically. We are not multiplying the matrices: we are choosing the least expensive order.

(A₁Aā‚‚)Aā‚ƒ

10Ā·30Ā·5 + 10Ā·5Ā·60 = 4 500

A₁(Aā‚‚Aā‚ƒ)

30Ā·5Ā·60 + 10Ā·30Ā·60 = 27 000

A chain of n matrices is described by the vector p[0…n]: Aįµ¢ has dimensions p[iāˆ’1] Ɨ p[i].

State, base case and recurrence

m[i,j] is the minimum number of scalar multiplications needed to compute Aᵢ…Aā±¼. s[i,j] stores the value of k that achieves that minimum.

m[i,i]=0 m[i,j]= mini≤k<j {m[i,k]+ m[k+1,j]+ p[iāˆ’1]p[k]p[j]}

Chains of length 1 cost zero. For a longer chain, try every last split k: the left cost, the right cost and the cost of multiplying the two results.

Lab: fill the rotated tables

As in the board diagram, the base-case diagonal sits at the bottom. Each new diagonal moves up one level: when a cell is evaluated, every cell it depends on is already filled.

Enter 3 to 9 positive numbers to create 2 to 8 compatible matrices.
Examples
Mminimum costs m[i,j]
Soptimal splits s[i,j]

Current calculation m[i,j]

Play the animation to compare splits.

Length ā„“
1
Cell
—
Split k
—
Comparisons
0
Synchronized pseudocode
  1. for i ← 1 to n: m[i,i] ← 0
  2. for ā„“ ← 2 to n
  3.   for i ← 1 to n āˆ’ ā„“ + 1
  4.     j ← i + ā„“ āˆ’ 1
  5.     m[i,j] ← āˆž
  6.     for k ← i to j āˆ’ 1
  7.       q ← m[i,k] + m[k+1,j] + p[iāˆ’1]p[k]p[j]
  8.       if q < m[i,j]: m[i,j] ← q
  9.         s[i,j] ← k
Current solution

—

Optimal cost: —

target cell used subproblems new minimum completed cell

Table S reconstructs the parentheses

M stores the optimal value but not the choices that produced it. S stores each split: starting from s[1,n], recursively reconstruct A₁…Aā‚– and then Aā‚–ā‚Šā‚ā€¦Aā‚™.

Print(i,j) → if i = j print Aįµ¢; otherwise print ā€œ(ā€, Print(i,s[i,j]), Print(s[i,j]+1,j), ā€œ)ā€.

General pattern. When you need the solution rather than only its value, store the best decision alongside each state value.

Correctness and complexity analysis

When evaluating m[i,j], every parenthesization has one final multiplication splitting the chain into Aᵢ…Aā‚– and Aā‚–ā‚Šā‚ā€¦Aā±¼ for a unique k. By optimal substructure, if either side were not optimal, replacing it would improve the global solution. Trying every k and taking the minimum is therefore sufficient.

ResourceCostWhy
SubproblemsΘ(n²)One cell for each interval [i,j].
TimeΘ(n³)Up to nāˆ’1 splits are tried for each interval.
SpaceΘ(n²)The two triangular tables M and S.
ReconstructionΘ(n)The parenthesization contains n matrices and nāˆ’1 splits.

Common mistakes

  • Confusing the number n of matrices with the n+1 length of vector p.
  • Using p[i], p[k] and p[j] instead of p[iāˆ’1], p[k] and p[j] for the final multiplication cost.
  • Filling by rows: m[i,j] depends on shorter intervals, so increasing chain length is the safe order.
  • Storing the cost in S: S contains index k, not value q.
  • Assuming the algorithm performs multiplication: it only computes the optimal order.

Exercises to consolidate the method

  1. Try p = [10, 20, 30, 40]. Before playing, manually compute the two candidates for m[1,3].
  2. In the lesson example, locate the cells used to evaluate m[2,5] when k = 3.
  3. Find a four-matrix chain where left-to-right parenthesization is optimal, and one where it is worst.
  4. Conceptually modify the algorithm to count how many parenthesizations achieve the same minimum cost.