浅谈区间 DP & 例题洛谷 P4170

区间 DP 简单概述

前传:简单线性 DP 详解

区间动态规划是动态规划的一个分支,主要用于解决具有区间性质的问题,特别是涉及到区间的分割、合并或者区间间某种依赖关系的题目。

区间 DP 概念较好理解,实战的话主要是思考难度高一点点。

思路可以总结为八个字:枚举断点,更新区间。

在这点下,和 最短路 Floyd 算法 较为相似。

区间 DP 的状态通常设定为:\(f_{i, j}\) 表示区间 \([i, j]\) 中的一个值。

区间 DP 通常是由两个较小的区间合并答案转移成大区间的答案,因此转移方程通常为:\(f_{i, j} = \max(f_{i, j}, f_{i, k} + f_{k + 1, j} + \dots)\),其中 \(\dots\) 表示可能的”计算更新信息“的方式。

由于区间 DP 的转移通常为从两个较小的区间转移过来,因此我们需要先计算小空间的值,再计算较大空间的值。所以区间 DP 通常最外层循环就需要枚举区间长度。

本题思路

状态:\(dp_{i, j}\) 表示将区间 \([i, j]\) 涂成目标颜色所需要的最少操作次数。

初始化:当区间只有一个字符时,只需要一次涂色操作将这个位置涂成目标颜色。

\[dp_{i, i} = 1 \]

对于长度大于 \(1\) 的区间 \([i, j]\),可以考虑:

  1. 假设我们先把区间 \([i, j - 1]\) 都涂好,最后再单独给位置 \(j\) 涂色,这样操作数就是:

\[dp_{i, j} = dp_{i, j - 1} + 1 \]

  1. 如果在区间 \([i, j - 1]\) 中存在一个位置 \(k\),满足 \(s_k = s_j\),则说明位置 \(k\) 与位置 \(j\) 的目标颜色相同。

    此时,我们可以考虑这样一种策略:

    • 先将区间 \([i, k]\) 涂好,使得位置 \(k\) 是正确的颜色。
    • 然后涂好部分 \([k + 1, j - 1]\)
    • 最后,由于 \(k\)\(j\) 的颜色相同,我们可以在最后一次操作中“顺带”让位置 \(j\) 也变成目标颜色,从而不需要额外的操作来单独处理 \(j\)

\[dp_{i, j} = dp_{i, k} + dp_{k + 1, j - 1} \]

我们遍历所有满足 \(s_k = s_j\)\(k\) 值,取其中最小的操作数,即:

\[dp_{i, j} = \min \Bigl( dp_{i, j - 1} + 1, \min_{i \le k < j \text{ 且 } s_k = s_j} \bigl(dp_{i, k} + dp{k + 1, j - 1} \bigr) \Bigr) \]

我们可以根据长度来递推整个过程。

代码如下:

#include <bits/stdc++.h> 
using namespace std;

string s;
int n;
int dp[55][55];

int main()
{
    cin >> s;
    n = s.size();
    s = " " + s;
    for (int i = 1; i <= n; i++)
        dp[i][i] = 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] = dp[i][j - 1] + 1;
            for (int k = i; k < j; k++)
            {
                if (s[k] == s[j])
                {
                    int x = dp[i][k];
                    if (k + 1 <= j - 1)
                        x += dp[k + 1][j - 1];
                    dp[i][j] = min(dp[i][j], x);
                }
            }
        }
    }
    
    cout << dp[1][n] << "\n";
    return 0;
}
posted @ 2025-03-23 11:45  George0915  阅读(48)  评论(0)    收藏  举报