PrepStack · Markdown HTML

区间 DP

动态规划 · HTML

数学 / 逻辑形态

dp[l][r] 表示闭区间 [l,r] 的最优值/计数。按长度递增,枚举 k:dp[l][r]=Aggregate_k(Combine(dp[l][k],dp[k+1][r],local(l,k,r))),或由去掉一端的状态转移。

识别信号

容易误判的相似信号

SignalWhy it is different
独立不相交区间选择若只按端点选择兼容区间,排序贪心或 weighted interval DP 更直接。
任意子集而非连续区间两个端点不能表达被挖空的集合,需 bitmask/其他状态。
局部合并代价固定且可贪心若有可证明的交换规则,不必承担 O(n³) 区间 DP。

核心不变量

计算长度 len 的区间前,所有更短依赖区间均已正确;dp[l][r] 枚举了该区间所有合法最后动作。

状态、转移与处理顺序

ItemDefinition
State闭区间端点 (l,r) 的最优值/方案数;可保存 split[l][r] 重构结构。
Transition枚举最后分割 k 或两端配对/删除动作,把更短区间答案与局部代价组合。
Frontier / order区间长度从短到长;同长度内 l 任意,r=l+len-1。

Python 骨架

def min_merge_cost(values):
    n = len(values)
    if n <= 1: return 0
    prefix = [0]
    for x in values: prefix.append(prefix[-1] + x)
    dp = [[0] * n for _ in range(n)]
    for length in range(2, n + 1):
        for l in range(n - length + 1):
            r = l + length - 1
            total = prefix[r + 1] - prefix[l]
            dp[l][r] = min(
                dp[l][k] + dp[k + 1][r] + total
                for k in range(l, r)
            )
    return dp[0][n - 1]

正确性思路

  1. 长度 0/1 无需合并,base 正确。
  2. 任一完整合并结构都有唯一最后一次分割 k,其两侧是更短区间。
  3. 归纳假设两侧最优,枚举全部 k 后取最优,既不漏结构也不会比真正最优差。

复杂度

TimeSpaceParameters
典型 O(n³),若转移可优化则可能 O(n²)O(n²)n 为序列长度;每区间枚举 O(n) 个 split。

边界条件

错误模式

PatternWhy it fails / fix
按 l/r 自然顺序填表大区间可能读到尚未计算的短区间;应按长度拓扑序。
split 边界重叠或漏项若左为 [l,k],右必须是 [k+1,r],且 k 范围 l..r-1。
把局部总代价重复/漏加明确代价属于最后一次合并还是子问题内部。
轻率声称 O(n²)n² 个区间再枚举 n 个 k,默认是 O(n³)。

选择与排除规则

相关模板

RelationTemplateBoundary
contrast区间排序贪心外部区间选择可由端点贪心,而非内部括号化。
alternative中心扩展 / Manacher 回文只需回文半径或最长回文子串。

原创微型例子

环节内容
Resultdp[0][2]=9,最后 split 在第二堆之后。
Setup三堆重量 [2,1,3],相邻两堆合并代价为新堆总重。
Trace先合 2+1 成本 3,再与 3 合成本 6,总 9;另一顺序为 4+6=10。

Recall prompts

我的补充