区间动态规划例题:最小涂色次数问题(环形版本)
字数 1429 2025-11-07 12:32:50

区间动态规划例题:最小涂色次数问题(环形版本)

题目描述
有一个环形栅栏由n个木桩组成,每个木桩需要涂上特定的颜色。给定一个长度为n的环形颜色数组colors,其中colors[i]表示第i个木桩的颜色。每次涂色操作可以选择一段连续的木桩,将它们涂成同一种颜色。但涂色会覆盖之前的颜色。问最少需要多少次涂色操作才能让所有木桩涂上目标颜色。

注意:由于是环形,第一个木桩和最后一个木桩是相邻的。

解题思路
这个问题是"奇怪的打印机"问题的环形版本。我们需要将环形问题转化为线性问题来处理。

关键步骤分析

  1. 环形转线性:由于是环形结构,我们可以通过破环成链的技巧,将原数组复制一份接在后面,形成长度为2n的线性数组。

  2. 状态定义:定义dp[i][j]表示完成区间[i,j]的木桩涂色所需的最小操作次数。

  3. 状态转移分析

    • 如果colors[i] == colors[j],那么我们可以先涂整个区间,再调整中间部分
    • 否则,我们需要在区间内找到一个分割点k,将区间分为[i,k]和[k+1,j]两部分
  4. 边界条件:单个木桩只需要1次操作。

详细解题过程

步骤1:问题转化
将环形数组colors复制一份:newColors = colors + colors
现在问题转化为在长度为2n的数组上,找到所有长度为n的区间中的最小涂色次数。

步骤2:状态定义
定义dp[i][j]:完成区间[i,j]涂色的最小操作次数。

步骤3:状态转移方程

  1. 当i == j时,dp[i][j] = 1(单个木桩需要1次操作)

  2. 当colors[i] == colors[j]时:
    dp[i][j] = min(dp[i+1][j], dp[i][j-1])
    因为如果两端颜色相同,我们可以用一次操作涂整个区间,或者利用另一端的扩展

  3. 当colors[i] != colors[j]时:
    我们需要在区间[i,j]内找到一个分割点k(i ≤ k < j):
    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j])

步骤4:环形处理
对于环形问题,我们需要计算所有可能的起点:
result = min(dp[i][i+n-1]),其中i从0到n-1

步骤5:算法实现
采用标准的区间DP遍历方式:按区间长度从小到大计算。

举例说明
假设colors = [1,2,1,2](环形)

破环成链后:[1,2,1,2,1,2,1,2]

计算过程:

  • 长度为1的区间:dp[i][i] = 1
  • 长度为2的区间:
    dp[0][1]:颜色不同,min(dp[0][0]+dp[1][1]) = 1+1 = 2
    dp[1][2]:颜色不同,min(dp[1][1]+dp[2][2]) = 1+1 = 2
  • 长度为3的区间:
    dp[0][2]:两端相同(1==1),min(dp[1][2], dp[0][1]) = min(2,2) = 2
  • 长度为4的区间(原环形长度):
    计算所有起点长度为4的区间,取最小值

最终得到最小涂色次数为2。

复杂度分析

  • 时间复杂度:O(n³),需要三重循环
  • 空间复杂度:O(n²),用于存储DP表

这个解法通过破环成链巧妙处理了环形结构,是区间DP处理环形问题的典型方法。

区间动态规划例题:最小涂色次数问题(环形版本) 题目描述 有一个环形栅栏由n个木桩组成,每个木桩需要涂上特定的颜色。给定一个长度为n的环形颜色数组colors,其中colors[ i ]表示第i个木桩的颜色。每次涂色操作可以选择一段连续的木桩,将它们涂成同一种颜色。但涂色会覆盖之前的颜色。问最少需要多少次涂色操作才能让所有木桩涂上目标颜色。 注意:由于是环形,第一个木桩和最后一个木桩是相邻的。 解题思路 这个问题是"奇怪的打印机"问题的环形版本。我们需要将环形问题转化为线性问题来处理。 关键步骤分析 环形转线性 :由于是环形结构,我们可以通过破环成链的技巧,将原数组复制一份接在后面,形成长度为2n的线性数组。 状态定义 :定义dp[ i][ j]表示完成区间[ i,j ]的木桩涂色所需的最小操作次数。 状态转移分析 : 如果colors[ i] == colors[ j ],那么我们可以先涂整个区间,再调整中间部分 否则,我们需要在区间内找到一个分割点k,将区间分为[ i,k]和[ k+1,j ]两部分 边界条件 :单个木桩只需要1次操作。 详细解题过程 步骤1:问题转化 将环形数组colors复制一份:newColors = colors + colors 现在问题转化为在长度为2n的数组上,找到所有长度为n的区间中的最小涂色次数。 步骤2:状态定义 定义dp[ i][ j]:完成区间[ i,j ]涂色的最小操作次数。 步骤3:状态转移方程 当i == j时,dp[ i][ j ] = 1(单个木桩需要1次操作) 当colors[ i] == colors[ j ]时: dp[ i][ j] = min(dp[ i+1][ j], dp[ i][ j-1 ]) 因为如果两端颜色相同,我们可以用一次操作涂整个区间,或者利用另一端的扩展 当colors[ i] != colors[ j ]时: 我们需要在区间[ i,j]内找到一个分割点k(i ≤ k < j): dp[ i][ j] = min(dp[ i][ j], dp[ i][ k] + dp[ k+1][ j ]) 步骤4:环形处理 对于环形问题,我们需要计算所有可能的起点: result = min(dp[ i][ i+n-1 ]),其中i从0到n-1 步骤5:算法实现 采用标准的区间DP遍历方式:按区间长度从小到大计算。 举例说明 假设colors = [ 1,2,1,2 ](环形) 破环成链后:[ 1,2,1,2,1,2,1,2 ] 计算过程: 长度为1的区间:dp[ i][ i ] = 1 长度为2的区间: dp[ 0][ 1]:颜色不同,min(dp[ 0][ 0]+dp[ 1][ 1 ]) = 1+1 = 2 dp[ 1][ 2]:颜色不同,min(dp[ 1][ 1]+dp[ 2][ 2 ]) = 1+1 = 2 长度为3的区间: dp[ 0][ 2]:两端相同(1==1),min(dp[ 1][ 2], dp[ 0][ 1 ]) = min(2,2) = 2 长度为4的区间(原环形长度): 计算所有起点长度为4的区间,取最小值 最终得到最小涂色次数为2。 复杂度分析 时间复杂度:O(n³),需要三重循环 空间复杂度:O(n²),用于存储DP表 这个解法通过破环成链巧妙处理了环形结构,是区间DP处理环形问题的典型方法。