石子合并问题(环形版本)
字数 954 2025-10-26 19:15:22

石子合并问题(环形版本)

题目描述
有N堆石子排成一个环形,每堆石子的数量用数组stones表示。每次操作可以将相邻的两堆石子合并成一堆,合并的代价是这两堆石子的数量之和。请找出将所有石子合并成一堆的最小总代价。

解题思路

  1. 环形问题可以通过将原数组复制一份接在后面,转化为长度为2N的线性问题
  2. 定义dp[i][j]表示合并第i到第j堆石子的最小代价
  3. 使用前缀和数组快速计算区间和
  4. 遍历所有可能的区间长度和起点,计算最小合并代价

详细步骤

步骤1:处理环形结构

  • 将原数组复制一份:newStones = stones + stones
  • 这样环形问题就转化为长度为2N的线性数组问题
  • 我们需要在长度为N的窗口内寻找最优解

步骤2:定义状态和前缀和

  • 定义dp[i][j]为合并第i到第j堆石子的最小代价
  • 定义前缀和数组preSum,其中preSum[i]表示前i堆石子的总和
  • 区间[i,j]的石子总和为preSum[j+1] - preSum[i]

步骤3:状态转移方程

  • 对于区间[i,j],考虑最后一次合并的位置k
  • 将区间分为[i,k]和[k+1,j]两部分
  • 合并代价 = dp[i][k] + dp[k+1][j] + (区间[i,j]的石子总和)
  • 状态转移方程:dp[i][j] = min(dp[i][k] + dp[k+1][j]) + sum(i,j),其中k从i到j-1

步骤4:初始化边界条件

  • 当区间长度为1时(即i=j),不需要合并,代价为0
  • 当区间长度为2时,合并代价就是两堆石子之和

步骤5:动态规划求解

  • 按区间长度从小到大进行遍历
  • 对于每个起点i,计算终点j = i + len - 1
  • 遍历所有可能的分割点k,找到最小代价

步骤6:寻找最终答案

  • 在转化后的2N数组中,检查所有长度为N的区间
  • 最小代价为min(dp[i][i+N-1]),其中i从0到N-1

示例分析
假设石子堆为[1,2,3,4](环形):

  • 转化为线性数组:[1,2,3,4,1,2,3,4]
  • 计算所有长度为4的区间的最小合并代价
  • 最终答案为这些代价中的最小值

这种方法通过复制数组巧妙地将环形问题转化为线性问题,确保了算法的正确性和效率。

石子合并问题(环形版本) 题目描述 有N堆石子排成一个环形,每堆石子的数量用数组stones表示。每次操作可以将相邻的两堆石子合并成一堆,合并的代价是这两堆石子的数量之和。请找出将所有石子合并成一堆的最小总代价。 解题思路 环形问题可以通过将原数组复制一份接在后面,转化为长度为2N的线性问题 定义dp[ i][ j ]表示合并第i到第j堆石子的最小代价 使用前缀和数组快速计算区间和 遍历所有可能的区间长度和起点,计算最小合并代价 详细步骤 步骤1:处理环形结构 将原数组复制一份:newStones = stones + stones 这样环形问题就转化为长度为2N的线性数组问题 我们需要在长度为N的窗口内寻找最优解 步骤2:定义状态和前缀和 定义dp[ i][ j ]为合并第i到第j堆石子的最小代价 定义前缀和数组preSum,其中preSum[ i ]表示前i堆石子的总和 区间[ i,j]的石子总和为preSum[ j+1] - preSum[ i ] 步骤3:状态转移方程 对于区间[ i,j ],考虑最后一次合并的位置k 将区间分为[ i,k]和[ k+1,j ]两部分 合并代价 = dp[ i][ k] + dp[ k+1][ j] + (区间[ i,j ]的石子总和) 状态转移方程:dp[ i][ j] = min(dp[ i][ k] + dp[ k+1][ j ]) + sum(i,j),其中k从i到j-1 步骤4:初始化边界条件 当区间长度为1时(即i=j),不需要合并,代价为0 当区间长度为2时,合并代价就是两堆石子之和 步骤5:动态规划求解 按区间长度从小到大进行遍历 对于每个起点i,计算终点j = i + len - 1 遍历所有可能的分割点k,找到最小代价 步骤6:寻找最终答案 在转化后的2N数组中,检查所有长度为N的区间 最小代价为min(dp[ i][ i+N-1 ]),其中i从0到N-1 示例分析 假设石子堆为[ 1,2,3,4 ](环形): 转化为线性数组:[ 1,2,3,4,1,2,3,4 ] 计算所有长度为4的区间的最小合并代价 最终答案为这些代价中的最小值 这种方法通过复制数组巧妙地将环形问题转化为线性问题,确保了算法的正确性和效率。