区间动态规划例题:合并相邻石子堆的最大得分问题(每次合并的得分为两堆石子数量之和的立方,求最大总得分)
字数 2591 2025-12-19 14:53:42

区间动态规划例题:合并相邻石子堆的最大得分问题(每次合并的得分为两堆石子数量之和的立方,求最大总得分)

题目描述

我们有一排石子堆,排成一个线性数组 stones,其中 stones[i] 表示第 i 堆石子的数量。游戏的目标是通过一系列的合并操作,将所有石子堆合并为一堆。在每次操作中,你可以选择相邻的两堆石子进行合并,合并后形成一堆新的石子堆,其石子数量等于原来两堆石子数量之和,并且本次合并的得分被定义为两堆石子数量之和的立方。你需要设计一种合并顺序,使得整个过程中获得的总得分最大。要求计算最大总得分。

示例

输入: stones = [1, 2, 3]
输出: 90
解释: 
一种最优合并顺序:
1. 合并 (1, 2) -> 新堆 [3, 3],得分 = (1+2)^3 = 27
2. 合并 (3, 3) -> 新堆 [6],得分 = (3+3)^3 = 216
总得分 = 27 + 216 = 243? 不对,让我们重新计算实际过程。
注意:第一次合并后,数组变成 [3, 3];第二次合并的是这两个3,得分 (3+3)^3 = 216。总得分 = 27 + 216 = 243,而不是90。所以 90 是怎么来的?
实际上,我们仔细看题目:每次合并的得分是“两堆石子数量之和的立方”,但合并后新的堆会替代原来两堆的位置,后续的合并是基于新堆的数量计算的。所以对于 [1,2,3]:
- 先合并 1 和 2:得分 (1+2)^3 = 27,新数组 [3,3]
- 再合并 3 和 3:得分 (3+3)^3 = 216,新数组 [6]
总得分 = 27 + 216 = 243
但示例输出是 90,这提示我们可能理解有误。实际上,示例可能是在每次合并时,得分并不是用“合并后新堆的数量”的立方,而是用“被合并的两堆的原始数量之和”的立方?不对,因为每次合并的两堆可能是之前合并产生的新堆,其数量是原始子数组的和。实际上,这里的“立方”得分是基于当前两堆的石子总数,也就是它们所代表的原始区间和。
所以我们重新计算 [1,2,3]:
- 先合并 1 和 2:两堆数量分别是1和2,和=3,得分 3^3 = 27,新堆数量3
- 再合并 3 和 3:两堆数量分别是3和3,和=6,得分 6^3 = 216
总得分 243,但示例输出是 90,说明题目可能不是立方,而是平方?但题目明确写了立方。这可能是示例错误,或者题目实际定义是平方。为了避免混淆,我们假定题目是“立方”,但为了示例合理,我们先用平方来理解示例。
实际上,如果得分为平方:
- 先合并1和2:得分 (1+2)^2=9,新堆3
- 再合并3和3:得分 (3+3)^2=36
总得分=45,也不是90。
如果先合并2和3:得分 (2+3)^2=25,新数组[1,5];再合并1和5:得分 (1+5)^2=36,总得分=61,也不是90。
如果得分为乘积:(1+2)*? 也不对。
所以,为了澄清,我们假设题目中“立方”是正确描述,示例输出可能是另一组数据的结果。在讲解中,我们专注于“立方”这一设定。

为了讲解清晰,我们重新定义示例,使其与立方得分一致:
假设 stones = [1, 2, 3],最大得分是 243,如上述计算。但可能还有另一种合并顺序:先合并 2 和 3:

  • 合并 (2,3):得分 (2+3)^3 = 125,新堆 [1,5]
  • 合并 (1,5):得分 (1+5)^3 = 216
    总得分 = 125+216 = 341,比243大。所以 341 才是最大得分。因此,不同的合并顺序会导致不同总得分,我们需要找到最大值。

问题形式化
给定数组 stones[0..n-1],定义 dp[i][j] 为将第 i 堆到第 j 堆(闭区间)合并为一堆所能获得的最大总得分。最终要求的是 dp[0][n-1]

注意:合并过程中,每次合并的得分是“被合并的两堆的石子数量之和”的立方。这两堆的石子数量,实际上是它们所代表的原始子数组的和。因此,我们需要快速计算任意区间 [i, j] 的石子总数,可以用前缀和数组 prefixSum 来得到,其中 prefixSum[k] 表示前 k 堆石子的总数量(一般定义 prefixSum[0]=0,prefixSum[i]=sum(stones[0..i-1])),那么区间和 sum(i,j) = prefixSum[j+1] - prefixSum[i]。

状态设计
dp[i][j] 表示将区间 [i, j] 内的所有石子堆合并为一堆所能获得的最大总得分。当区间长度为 1 时,只有一堆,不需要合并,得分为 0。

状态转移
考虑区间 [i, j],我们如何将其合并为一堆?最后一步合并一定是将 [i, j] 分成两个连续区间 [i, k] 和 [k+1, j],分别将它们各自合并为一堆,然后再将这两堆合并。因此,总得分 = 将左边区间合并为一堆的最大得分 + 将右边区间合并为一堆的最大得分 + 最后合并这两堆的得分。
其中,最后合并的得分是 (sum(i,k) + sum(k+1,j))^3,但 sum(i,k) 是左边区间合并后那堆的石子数,sum(k+1,j) 是右边区间合并后那堆的石子数,它们的和正是整个区间 [i, j] 的石子总数,即 sum(i,j)。所以最后合并的得分 = (sum(i,j))^3。

因此,状态转移方程为:

dp[i][j] = max{ dp[i][k] + dp[k+1][j] } + (sum(i,j))^3,其中 k 从 i 到 j-1

注意:当 i == j 时,区间只有一堆,dp[i][j] = 0。

计算顺序
由于 dp[i][j] 依赖于更短的区间(即长度小于 j-i+1 的区间),所以我们按照区间长度从小到大计算。先计算所有长度为 1 的区间(得分0),然后长度 2, 3, ..., n。

最终答案
dp[0][n-1]

示例计算(stones = [1,2,3])
n=3,前缀和 prefixSum: [0,1,3,6](prefixSum[i] 表示前 i 个元素和,i 从0到n)。
区间和 sum(i,j) = prefixSum[j+1] - prefixSum[i]。

  • 长度1:dp[0][0]=0, dp[1][1]=0, dp[2][2]=0。
  • 长度2:
    • 区间 [0,1]: sum=1+2=3,得分=3^3=27。只有一种划分(k=0):dp[0][0]+dp[1][1]+27=0+0+27=27,所以 dp[0][1]=27。
    • 区间 [1,2]: sum=2+3=5,得分=125。dp[1][2]=0+0+125=125。
  • 长度3:区间 [0,2],sum=1+2+3=6,得分=216。
    划分点 k=0:dp[0][0]+dp[1][2]+216 = 0+125+216 = 341
    划分点 k=1:dp[0][1]+dp[2][2]+216 = 27+0+216 = 243
    取最大值:dp[0][2]=max(341,243)=341。
    所以最大总得分为 341。

时间复杂度
状态数 O(n^2),每个状态需要枚举划分点 k,O(n) 种可能,总时间复杂度 O(n^3)。空间复杂度 O(n^2)。

优化考虑
对于区间DP,O(n^3) 是常规复杂度,在 n 较小时可行(例如 n <= 200)。如果 n 更大,可能需要优化,但本题通常设定 n 在 100 左右,因此直接 DP 即可。

实现细节

  1. 计算前缀和数组 prefixSum。
  2. 初始化 dp 数组,所有元素为0(因为长度为1时得分为0)。
  3. 按长度 len 从 2 到 n 遍历。
  4. 对于每个起点 i,计算终点 j = i+len-1。
  5. 计算区间和 total = prefixSum[j+1] - prefixSum[i]。
  6. 枚举划分点 k 从 i 到 j-1,计算 dp[i][k] + dp[k+1][j] + total^3 的最大值,赋给 dp[i][j]。

边界情况

  • 如果 n=0,没有石子堆,得分为0。
  • 如果 n=1,只有一堆,不需要合并,得分为0。

总结
这道题是经典的“石子合并”问题的变体,区别在于合并得分函数从“两堆石子数量之和”变为“和的三次方”。三次方的引入使得得分增长更快,可能会影响最优合并顺序(因为大数立方增长极快,倾向于尽早合并大数?),但状态转移方程的结构保持不变,仍然是通过枚举最后合并的分界点来求解。通过区间DP,我们可以在 O(n^3) 时间内求解最大总得分。

希望这个讲解让你清晰理解这个问题的解法。

区间动态规划例题:合并相邻石子堆的最大得分问题(每次合并的得分为两堆石子数量之和的立方,求最大总得分) 题目描述 我们有一排石子堆,排成一个线性数组 stones ,其中 stones[i] 表示第 i 堆石子的数量。游戏的目标是通过一系列的合并操作,将所有石子堆合并为一堆。在每次操作中,你可以选择相邻的两堆石子进行合并,合并后形成一堆新的石子堆,其石子数量等于原来两堆石子数量之和,并且本次合并的得分被定义为 两堆石子数量之和的立方 。你需要设计一种合并顺序,使得整个过程中获得的总得分最大。要求计算最大总得分。 示例 : 为了讲解清晰,我们重新定义示例,使其与立方得分一致: 假设 stones = [ 1, 2, 3 ],最大得分是 243,如上述计算。但可能还有另一种合并顺序:先合并 2 和 3: 合并 (2,3):得分 (2+3)^3 = 125,新堆 [ 1,5 ] 合并 (1,5):得分 (1+5)^3 = 216 总得分 = 125+216 = 341,比243大。所以 341 才是最大得分。因此,不同的合并顺序会导致不同总得分,我们需要找到最大值。 问题形式化 : 给定数组 stones[0..n-1] ,定义 dp[i][j] 为将第 i 堆到第 j 堆(闭区间)合并为一堆所能获得的最大总得分。最终要求的是 dp[0][n-1] 。 注意:合并过程中,每次合并的得分是“被合并的两堆的石子数量之和”的立方。这两堆的石子数量,实际上是它们所代表的原始子数组的和。因此,我们需要快速计算任意区间 [ i, j] 的石子总数,可以用前缀和数组 prefixSum 来得到,其中 prefixSum[k] 表示前 k 堆石子的总数量(一般定义 prefixSum[ 0]=0,prefixSum[ i]=sum(stones[ 0..i-1])),那么区间和 sum(i,j) = prefixSum[ j+1] - prefixSum[ i ]。 状态设计 : dp[i][j] 表示将区间 [ i, j ] 内的所有石子堆合并为一堆所能获得的最大总得分。当区间长度为 1 时,只有一堆,不需要合并,得分为 0。 状态转移 : 考虑区间 [ i, j],我们如何将其合并为一堆?最后一步合并一定是将 [ i, j] 分成两个连续区间 [ i, k] 和 [ k+1, j ],分别将它们各自合并为一堆,然后再将这两堆合并。因此,总得分 = 将左边区间合并为一堆的最大得分 + 将右边区间合并为一堆的最大得分 + 最后合并这两堆的得分。 其中,最后合并的得分是 (sum(i,k) + sum(k+1,j))^3,但 sum(i,k) 是左边区间合并后那堆的石子数,sum(k+1,j) 是右边区间合并后那堆的石子数,它们的和正是整个区间 [ i, j ] 的石子总数,即 sum(i,j)。所以最后合并的得分 = (sum(i,j))^3。 因此,状态转移方程为: 注意:当 i == j 时,区间只有一堆,dp[ i][ j ] = 0。 计算顺序 : 由于 dp[ i][ j ] 依赖于更短的区间(即长度小于 j-i+1 的区间),所以我们按照区间长度从小到大计算。先计算所有长度为 1 的区间(得分0),然后长度 2, 3, ..., n。 最终答案 : dp[0][n-1] 示例计算(stones = [ 1,2,3]) : n=3,前缀和 prefixSum: [ 0,1,3,6](prefixSum[ i ] 表示前 i 个元素和,i 从0到n)。 区间和 sum(i,j) = prefixSum[ j+1] - prefixSum[ i ]。 长度1:dp[ 0][ 0]=0, dp[ 1][ 1]=0, dp[ 2][ 2 ]=0。 长度2: 区间 [ 0,1]: sum=1+2=3,得分=3^3=27。只有一种划分(k=0):dp[ 0][ 0]+dp[ 1][ 1]+27=0+0+27=27,所以 dp[ 0][ 1 ]=27。 区间 [ 1,2]: sum=2+3=5,得分=125。dp[ 1][ 2 ]=0+0+125=125。 长度3:区间 [ 0,2 ],sum=1+2+3=6,得分=216。 划分点 k=0:dp[ 0][ 0]+dp[ 1][ 2 ]+216 = 0+125+216 = 341 划分点 k=1:dp[ 0][ 1]+dp[ 2][ 2 ]+216 = 27+0+216 = 243 取最大值:dp[ 0][ 2 ]=max(341,243)=341。 所以最大总得分为 341。 时间复杂度 : 状态数 O(n^2),每个状态需要枚举划分点 k,O(n) 种可能,总时间复杂度 O(n^3)。空间复杂度 O(n^2)。 优化考虑 : 对于区间DP,O(n^3) 是常规复杂度,在 n 较小时可行(例如 n <= 200)。如果 n 更大,可能需要优化,但本题通常设定 n 在 100 左右,因此直接 DP 即可。 实现细节 : 计算前缀和数组 prefixSum。 初始化 dp 数组,所有元素为0(因为长度为1时得分为0)。 按长度 len 从 2 到 n 遍历。 对于每个起点 i,计算终点 j = i+len-1。 计算区间和 total = prefixSum[ j+1] - prefixSum[ i ]。 枚举划分点 k 从 i 到 j-1,计算 dp[ i][ k] + dp[ k+1][ j] + total^3 的最大值,赋给 dp[ i][ j ]。 边界情况 : 如果 n=0,没有石子堆,得分为0。 如果 n=1,只有一堆,不需要合并,得分为0。 总结 : 这道题是经典的“石子合并”问题的变体,区别在于合并得分函数从“两堆石子数量之和”变为“和的三次方”。三次方的引入使得得分增长更快,可能会影响最优合并顺序(因为大数立方增长极快,倾向于尽早合并大数?),但状态转移方程的结构保持不变,仍然是通过枚举最后合并的分界点来求解。通过区间DP,我们可以在 O(n^3) 时间内求解最大总得分。 希望这个讲解让你清晰理解这个问题的解法。