Interval DPs run in instead of when the optimal split satisfies

Yao’s theorem: this holds when satisfies the quadrangle inequality and is monotone on inclusion, for . Merging adjacent piles (cost = range sum) and optimal BST (cost = frequency sum) qualify; matrix chain does not.

template<class W> ll knuth(int n, W w) {                   // half-open intervals [i, j) over 0..n
    vector<vector<ll>> dp(n + 1, vector<ll>(n + 1)); vector<vector<int>> opt(n + 1, vector<int>(n + 1));
    for (int i = 0; i < n; i++) opt[i][i + 1] = i;          // length 1 costs 0 here; adjust if leaves cost something
    for (int len = 2; len <= n; len++) for (int i = 0, j = len; j <= n; i++, j++) {
        dp[i][j] = LLONG_MAX;
        for (int k = max(i + 1, opt[i][j - 1]); k <= min(j - 1, opt[i + 1][j]); k++) {
            ll v = dp[i][k] + dp[k][j];
            if (v < dp[i][j]) dp[i][j] = v, opt[i][j] = k;
        }
        dp[i][j] += w(i, j);
    }
    return dp[0][n];
}

Optimal BST

Keys with access frequencies (and gap frequencies for unsuccessful searches): where is the total frequency in the range. is additive (QI with equality) and monotone on inclusion, so Knuth applies and gives Knuth’s original algorithm, with .

Merging adjacent piles in : Garsia–Wachs

Minimum total cost to merge piles in a line, each merge costing the merged size (equivalently, an optimal alphabetic binary tree with leaf weights , where the cost is ). Hu–Tucker and Garsia–Wachs solve it in ; the simple form of Garsia–Wachs is often enough:

ll garsiaWachs(vector<ll> a) {
    const ll INF = LLONG_MAX / 4; ll ans = 0;
    a.insert(a.begin(), INF); a.push_back(INF);
    while (sz(a) > 3) {
        int k = 1; while (a[k - 1] > a[k + 1]) k++;          // leftmost k with a[k-1] <= a[k+1]
        ll t = a[k - 1] + a[k]; ans += t;                     // merge a[k-1], a[k]
        a.erase(a.begin() + k - 1, a.begin() + k + 1);
        int j = k - 1; while (a[j - 1] < t) j--;              // move left past smaller elements
        a.insert(a.begin() + j, t);
    }
    return ans;
}

The result is the optimal cost, but the merge sequence above is not itself a valid sequence of adjacent merges: Garsia–Wachs computes optimal leaf depths, and an alphabetic tree with those depths always exists (it can be built left to right with a stack). This is the classical theorem behind Hu–Tucker; its proof is long (Kingston gives a readable one). If the piles form a circle, the problem needs the Knuth DP on the doubled array.

This is an alphabetic tree problem: unlike Huffman coding, the leaves must stay in their original left-to-right order (so comparing codes compares the original symbols) — that constraint is exactly why plain Huffman’s “merge the two globally smallest weights” is unsound here (the two smallest may not be adjacent), and why a dedicated algorithm is needed at all. If an exact answer isn’t actually required, Mehlhorn’s greedy heuristic gets within 2 bits of optimal in .

Applications beyond pile-merging: optimal alphabetic prefix codes, optimal BSTs built from successful-search frequencies only (Knuth’s original motivation), and any code-tree problem where physical/left-to-right ordering is fixed by the application (circuit design, ordered search trees).

Concave vs convex QI, by name: the inequality used above (concave QI) gives a monotone argmin for minimisation; the reversed inequality (convex QI) gives one for maximisation, and is the condition underlying the convex form of CHT and the SMAWK row-minima algorithm. Getting the direction backwards is a common silent bug — always re-check which form your cost satisfies.

Yao’s minimax principle (a separate, equally famous result by the same Yao, unrelated to the interval-DP optimisation beyond sharing an author): the expected cost of the best randomized algorithm against its worst input equals the cost of the best deterministic algorithm against the worst input distribution. This is the standard tool for randomized lower bounds — e.g. proving any randomized comparison sort needs expected comparisons.

When Knuth does not apply

  • Matrix chain: depends on the split point (), so the theorem doesn’t apply and counterexamples to monotonicity exist; use , or Hu–Shing if really needed.
  • Costs that depend on the split in general: try D&C on one endpoint if rows are Monge, else stay cubic.
  • Unverified costs: brute-force check QI and monotonicity on random small instances before trusting the speedup.