合并相邻同色字符的最小操作次数问题(每次操作可以合并两个相邻且颜色相同的字符,合并后生成一个新字符,且新字符颜色可能变化,并产生一定操作次数消耗,求将整个字符串合并为一个字符的最小操作次数)
字数 3071 2025-12-13 07:33:32

合并相邻同色字符的最小操作次数问题(每次操作可以合并两个相邻且颜色相同的字符,合并后生成一个新字符,且新字符颜色可能变化,并产生一定操作次数消耗,求将整个字符串合并为一个字符的最小操作次数)


问题描述

我们有一个长度为 \(n\) 的字符串 \(s\),其中每个字符有一个颜色(可以用整数表示)。
每次操作可以选择两个相邻且颜色相同的字符,将它们合并成一个新的字符。
新字符的颜色由一个给定的规则决定(例如通过查表,或者通过某种计算得到),并且每次操作需要消耗 1 次操作次数
目标是:通过一系列合并操作,最终将整个字符串合并为 一个字符,并且要求 总操作次数最小

注意:

  • 合并只能发生在相邻且颜色相同的字符之间。
  • 合并后,新字符的颜色可能和原颜色不同。
  • 如果相邻字符颜色不同,则不能合并。
  • 最终必须合并到只剩一个字符,如果无法合并到只剩一个字符,则返回 -1 或表示不可能。

通常,题目会给出一个 颜色转移表 \(trans[a][b]\),表示当两个颜色为 \(a\) 的字符合并时,生成的新颜色为 \(trans[a][b]\)(有时与 \(b\) 无关,只与 \(a\) 有关,即 \(trans[a]\))。


示例

假设颜色种类只有 0, 1, 2。
转移规则:

  • 两个颜色 0 合并 → 新颜色 1
  • 两个颜色 1 合并 → 新颜色 2
  • 两个颜色 2 合并 → 新颜色 0

字符串 \(s = [0, 1, 0, 1, 2]\)
我们想知道能否合并为一个字符,以及最少操作次数。


思路分析

这是一个典型的 区间动态规划 问题,因为合并操作会不断将相邻区间合并成一种颜色,最终整个区间变成一种颜色。

定义状态:
\(dp[i][j][c]\) = 能否将子串 \(s[i..j]\) 合并成颜色为 \(c\)单个字符,如果可以,最小操作次数是多少;如果不能,则为无穷大(或标记不可行)。

最终答案:
对所有可能的最终颜色 \(c\),取 \(dp[0][n-1][c]\) 的最小值。


状态转移推导

对于区间 \([i, j]\),我们想把它合并成颜色 \(c\)
如何合并?
最后一步合并时,区间 \([i, j]\) 由两个子区间 \([i, k]\)\([k+1, j]\) 分别合并成颜色 \(c_1\)\(c_2\),并且这两个颜色相同(因为只有相邻且颜色相同的字符才能合并),且合并后变成颜色 \(c\)

所以:

  1. 先让 \([i, k]\) 合并成颜色 \(c_1\)(操作次数 \(dp[i][k][c_1]\)
  2. 再让 \([k+1, j]\) 合并成颜色 \(c_2\)(操作次数 \(dp[k+1][j][c_2]\)
  3. 要求 \(c_1 = c_2\)(否则无法合并这两个区间)
  4. 根据规则,两个颜色 \(c_1\) 合并成新颜色 \(trans[c_1]\),这里必须等于 \(c\)
  5. 总操作次数 = \(dp[i][k][c_1] + dp[k+1][j][c_1] + 1\)(最后一步合并操作)

所以转移方程:

\[dp[i][j][c] = \min_{i \le k < j, \; c_1 \in colors} \left\{ dp[i][k][c_1] + dp[k+1][j][c_1] + 1 \right\} \]

其中要求 \(trans[c_1] = c\)(即合并后必须得到目标颜色 \(c\))。


初始条件

对于区间长度为 1 的情况:
\(dp[i][i][s[i]] = 0\)(已经是颜色 \(s[i]\),不需要合并)
\(dp[i][i][c] = \infty\)(对于其他颜色 \(c \neq s[i]\) 不可能)


计算顺序

区间 DP 通常按区间长度从小到大计算:

  1. 先算所有长度为 1 的区间
  2. 再算长度为 2 的区间:需要合并两个字符,它们颜色必须相同,才能合并成 \(trans[color]\),操作次数为 1
  3. 再算长度为 3, 4, ..., n 的区间

实现细节

设颜色种类数为 \(m\),字符串长度为 \(n\)
状态数组大小:\(dp[n][n][m]\)
时间复杂度:

  • 外层循环长度 \(len = 2\)\(n\)
  • 内层循环起点 \(i\)
  • 内层循环分割点 \(k\)
  • 枚举颜色 \(c_1\)(用于左右区间)
  • 然后得到新颜色 \(c = trans[c_1]\)
    总复杂度 \(O(n^3 \cdot m)\)

举例详细推演

假设颜色集合 {0,1,2},转移规则如上。
字符串 s = [0,1,0,1,2],长度 5。

初始化:
dp[0][0][0] = 0, 其他 dp[0][0][c]=∞
dp[1][1][1] = 0
dp[2][2][0] = 0
dp[3][3][1] = 0
dp[4][4][2] = 0

长度 2:
[0,1]: 颜色 0 和 1 不同,不能合并 → 对所有 c 都是 ∞
[1,2]: 1 和 0 不同 → ∞
[2,3]: 0 和 1 不同 → ∞
[3,4]: 1 和 2 不同 → ∞

长度 3:
以 [0,2] = [0,1,0] 为例:
可能的分割点 k=0,1
尝试 k=0: [0,0] 颜色 0, [1,2] 需要合并成颜色 0 才能和左边合并。检查 [1,2] 能否变成颜色 0。
[1,2] 长度 2,颜色分别是 1 和 0,不同,不能合并成任何颜色 → 不可能
k=1: [0,1] 需要变成颜色 c1, [2,2] 颜色 0。要合并,c1 必须等于 0,但 [0,1] 长度 2,不可能合并成颜色 0(因为 0 和 1 不同)。所以不可能。
因此 [0,2] 不能合并成一个字符。

我们跳过详细推演(篇幅有限),最终我们要检查整个 [0,4] 能否合并成某种颜色并求最小次数。

在实际问题中,可能有些状态可达,有些不可达。最终取 min(dp[0][n-1][c]) 若为 ∞ 则返回 -1。


优化思考

有时可以简化:
因为最后合并的两个区间颜色必须相同,所以我们可以定义另一个状态:
\(f[i][j]\) = 将 [i..j] 合并成一个字符的最少操作次数(不指定颜色),同时记录合并后的颜色。
但这样需要同时追踪颜色,否则不知道下一步合并规则。
常用方法还是三维 dp[i][j][c]。


小结

这个问题的核心是:

  1. 识别为区间 DP,因为合并相邻区间直到整个区间变成一个字符。
  2. 状态要包含最终颜色,因为合并规则依赖于颜色。
  3. 转移时,枚举最后一步合并的分割点,要求左右区间合并成相同颜色,再根据规则得到新区间颜色。

通过这个模板,你可以解决类似“合并相邻同色字符,颜色变化,求最小操作次数”的问题。

合并相邻同色字符的最小操作次数问题(每次操作可以合并两个相邻且颜色相同的字符,合并后生成一个新字符,且新字符颜色可能变化,并产生一定操作次数消耗,求将整个字符串合并为一个字符的最小操作次数) 问题描述 我们有一个长度为 \( n \) 的字符串 \( s \),其中每个字符有一个颜色(可以用整数表示)。 每次操作可以选择两个 相邻且颜色相同 的字符,将它们合并成一个新的字符。 新字符的颜色由一个给定的规则决定(例如通过查表,或者通过某种计算得到),并且每次操作需要消耗 1 次操作次数 。 目标是:通过一系列合并操作,最终将整个字符串合并为 一个字符 ,并且要求 总操作次数最小 。 注意: 合并只能发生在相邻且颜色相同的字符之间。 合并后,新字符的颜色可能和原颜色不同。 如果相邻字符颜色不同,则不能合并。 最终必须合并到只剩一个字符,如果无法合并到只剩一个字符,则返回 -1 或表示不可能。 通常,题目会给出一个 颜色转移表 \( trans[ a][ b] \),表示当两个颜色为 \( a \) 的字符合并时,生成的新颜色为 \( trans[ a][ b] \)(有时与 \( b \) 无关,只与 \( a \) 有关,即 \( trans[ a ] \))。 示例 假设颜色种类只有 0, 1, 2。 转移规则: 两个颜色 0 合并 → 新颜色 1 两个颜色 1 合并 → 新颜色 2 两个颜色 2 合并 → 新颜色 0 字符串 \( s = [ 0, 1, 0, 1, 2 ] \) 我们想知道能否合并为一个字符,以及最少操作次数。 思路分析 这是一个典型的 区间动态规划 问题,因为合并操作会不断将相邻区间合并成一种颜色,最终整个区间变成一种颜色。 定义状态: \( dp[ i][ j][ c] \) = 能否将子串 \( s[ i..j] \) 合并成颜色为 \( c \) 的 单个字符 ,如果可以,最小操作次数是多少;如果不能,则为无穷大(或标记不可行)。 最终答案: 对所有可能的最终颜色 \( c \),取 \( dp[ 0][ n-1][ c ] \) 的最小值。 状态转移推导 对于区间 \( [ i, j ] \),我们想把它合并成颜色 \( c \)。 如何合并? 最后一步合并时,区间 \( [ i, j] \) 由两个子区间 \( [ i, k] \) 和 \( [ k+1, j] \) 分别合并成颜色 \( c_ 1 \) 和 \( c_ 2 \),并且这两个颜色相同(因为只有相邻且颜色相同的字符才能合并),且合并后变成颜色 \( c \)。 所以: 先让 \( [ i, k] \) 合并成颜色 \( c_ 1 \)(操作次数 \( dp[ i][ k][ c_ 1 ] \)) 再让 \( [ k+1, j] \) 合并成颜色 \( c_ 2 \)(操作次数 \( dp[ k+1][ j][ c_ 2 ] \)) 要求 \( c_ 1 = c_ 2 \)(否则无法合并这两个区间) 根据规则,两个颜色 \( c_ 1 \) 合并成新颜色 \( trans[ c_ 1 ] \),这里必须等于 \( c \) 总操作次数 = \( dp[ i][ k][ c_ 1] + dp[ k+1][ j][ c_ 1 ] + 1 \)(最后一步合并操作) 所以转移方程: \[ dp[ i][ j][ c] = \min_ {i \le k < j, \; c_ 1 \in colors} \left\{ dp[ i][ k][ c_ 1] + dp[ k+1][ j][ c_ 1 ] + 1 \right\} \] 其中要求 \( trans[ c_ 1 ] = c \)(即合并后必须得到目标颜色 \( c \))。 初始条件 对于区间长度为 1 的情况: \( dp[ i][ i][ s[ i]] = 0 \)(已经是颜色 \( s[ i ] \),不需要合并) \( dp[ i][ i][ c] = \infty \)(对于其他颜色 \( c \neq s[ i ] \) 不可能) 计算顺序 区间 DP 通常按区间长度从小到大计算: 先算所有长度为 1 的区间 再算长度为 2 的区间:需要合并两个字符,它们颜色必须相同,才能合并成 \( trans[ color ] \),操作次数为 1 再算长度为 3, 4, ..., n 的区间 实现细节 设颜色种类数为 \( m \),字符串长度为 \( n \)。 状态数组大小:\( dp[ n][ n][ m ] \) 时间复杂度: 外层循环长度 \( len = 2 \) 到 \( n \) 内层循环起点 \( i \) 内层循环分割点 \( k \) 枚举颜色 \( c_ 1 \)(用于左右区间) 然后得到新颜色 \( c = trans[ c_ 1 ] \) 总复杂度 \( O(n^3 \cdot m) \) 举例详细推演 假设颜色集合 {0,1,2},转移规则如上。 字符串 s = [ 0,1,0,1,2 ],长度 5。 初始化: dp[ 0][ 0][ 0] = 0, 其他 dp[ 0][ 0][ c ]=∞ dp[ 1][ 1][ 1 ] = 0 dp[ 2][ 2][ 0 ] = 0 dp[ 3][ 3][ 1 ] = 0 dp[ 4][ 4][ 2 ] = 0 长度 2: [ 0,1 ]: 颜色 0 和 1 不同,不能合并 → 对所有 c 都是 ∞ [ 1,2 ]: 1 和 0 不同 → ∞ [ 2,3 ]: 0 和 1 不同 → ∞ [ 3,4 ]: 1 和 2 不同 → ∞ 长度 3: 以 [ 0,2] = [ 0,1,0 ] 为例: 可能的分割点 k=0,1 尝试 k=0: [ 0,0] 颜色 0, [ 1,2] 需要合并成颜色 0 才能和左边合并。检查 [ 1,2 ] 能否变成颜色 0。 [ 1,2 ] 长度 2,颜色分别是 1 和 0,不同,不能合并成任何颜色 → 不可能 k=1: [ 0,1] 需要变成颜色 c1, [ 2,2] 颜色 0。要合并,c1 必须等于 0,但 [ 0,1 ] 长度 2,不可能合并成颜色 0(因为 0 和 1 不同)。所以不可能。 因此 [ 0,2 ] 不能合并成一个字符。 我们跳过详细推演(篇幅有限),最终我们要检查整个 [ 0,4 ] 能否合并成某种颜色并求最小次数。 在实际问题中,可能有些状态可达,有些不可达。最终取 min(dp[ 0][ n-1][ c ]) 若为 ∞ 则返回 -1。 优化思考 有时可以简化: 因为最后合并的两个区间颜色必须相同,所以我们可以定义另一个状态: \( f[ i][ j] \) = 将 [ i..j] 合并成一个字符的 最少操作次数 (不指定颜色),同时记录合并后的颜色。 但这样需要同时追踪颜色,否则不知道下一步合并规则。 常用方法还是三维 dp[ i][ j][ c ]。 小结 这个问题的核心是: 识别为区间 DP,因为合并相邻区间直到整个区间变成一个字符。 状态要包含最终颜色,因为合并规则依赖于颜色。 转移时,枚举最后一步合并的分割点,要求左右区间合并成相同颜色,再根据规则得到新区间颜色。 通过这个模板,你可以解决类似“合并相邻同色字符,颜色变化,求最小操作次数”的问题。