测评会员优惠活动进行中 · 开通 VIP,有效期内测评不限次 VIP 优惠中 · 测评不限次 立即查看
官方题单 知识点专项

区间型DP入门

按区间长度递推,适合合并石子等区间最优问题。

开始练习 ← 返回广场
题数:20题
完成度:0/20

区间 DP



算法简介



区间 DP 主要用于解决 大区间的问题可以由小区间合并而来 的一类问题。核心思想是按照区间长度(由短到长)作为阶段进行枚举,将两个或多个较小的子区间合并为一个较大的区间。

  • 时间复杂度:通常为 $O(n^3)$
  • 基本枚举顺序:先枚举区间长度 $len$,再枚举左端点 $i$,最后枚举断点 $k$

  • ---

    一、代价合并模型



    1. 核心原理



    这是最基础的模型。问题通常描述为:将一些元素合并成一个大元素,每次合并产生一定的代价收益
  • 状态转移

  • $$ dp[i][j] = \max_{i \le k j} { dp[i][k] + dp[k+1][j] } + \text{cost}(i, j) $$

    其中 $k$ 为区间 $[i, j]$ 的分割点。

    ---

    2. 常用技巧


  • 断环成链
  • 处理环形问题(如项链、环形石子)时,将数组复制一份接在尾部:$a[1 \dots n] \rightarrow a[1 \dots 2n]$,
    最后在长度为 $n$ 的区间中找最优解。


    ---

    3. 代码模板



    // 代价合并通用模板
    for (int i = 1; i <= n; i++) {
        dp[i][i] = 0;
    }
    
    for (int len = 2; len <= n; len++) {
        for (int i = 1; i + len - 1 <= n; i++) {
            int j = i + len - 1;
            dp[i][j] = INF;
            for (int k = i; k < j; k++) {
                dp[i][j] = min(
                    dp[i][j],
                    dp[i][k] + dp[k + 1][j] + cost(i, j)
                );
            }
        }
    }


    ---

    二、特征消除模型



    1. 核心原理



    这类问题利用区间端点的特征(如字符相等)来优化转移,常见于回文串、涂色、祖玛游戏等。
  • 若 $a[i] = a[j]$,说明左右端点特征一致,区间 $[i, j]$ 可以直接由内部状态扩展而来(如 $dp[i+1][j-1]$),通常可以减少一次操作或降低代价。
  • 若 $a[i] \ne a[j]$,说明左右端点无法直接合并,必须枚举断点 $k$ 将区间拆分。

  • ---

    2. 代码模板



    // 特征消除 / 压缩类模板
    for (int len = 2; len <= n; len++) {
        for (int i = 1; i + len - 1 <= n; i++) {
            int j = i + len - 1;
    
            if (a[i] == a[j]) {
                dp[i][j] = ...; // 继承或压缩
            } else {
                dp[i][j] = INF;
            }
    
            for (int k = i; k < j; k++) {
                dp[i][j] = min(
                    dp[i][j],
                    dp[i][k] + dp[k + 1][j]
                );
            }
        }
    }


    ---

    三、状态扩展模型



    1. 核心原理



    当简单的 $dp[i][j]$ 无法完整描述当前局面时,需要增加维度
  • $dp[i][j][0]$:区间 $[i, j]$ 已处理完,最后停在左端点 $i$
  • $dp[i][j][1]$:区间 $[i, j]$ 已处理完,最后停在右端点 $j$
---

2. 代码模板



// 0 / 1 端点状态模板
for (int len = 2; len <= n; len++) {
    for (int i = 1; i + len - 1 <= n; i++) {
        int j = i + len - 1;

        dp[i][j][0] = min(
            dp[i + 1][j][0] + dist(i + 1, i),
            dp[i + 1][j][1] + dist(j, i)
        );

        dp[i][j][1] = min(
            dp[i][j - 1][0] + dist(i, j),
            dp[i][j - 1][1] + dist(j - 1, j)
        );
    }
}

【前置衔接知识点】
1、动态规划基础

【思维导图】




【题目知识点分类】