石子合并问题(每次合并的得分为两堆石子数量之和的立方,求最大总得分)
字数 3168 2025-12-21 01:04:08
石子合并问题(每次合并的得分为两堆石子数量之和的立方,求最大总得分)
这是一个在经典石子合并问题基础上的变体。我们通常熟悉的石子合并是求最小总成本,而这里不仅目标是最大化总得分,而且得分规则也改变了——每合并两堆石子,得分是这两堆石子数量之和的立方。这种立方关系使得合并较大的堆会带来极高的得分奖励,策略可能与线性或平方成本有所不同。
问题描述
你有一排 n 堆石子,排成一个线性数组。第 i 堆石子有 stones[i] 颗。游戏规则如下:
- 你每次只能合并相邻的两堆石子。
- 合并后,这两堆石子合并为一堆,新堆的石子数量是原来两堆石子数量之和。
- 本次合并的得分为两堆石子数量之和的立方。
- 合并过程一直进行,直到只剩下一堆石子为止。
你的目标是,通过选择合并的顺序,使得整个过程中获得的总得分最大。你需要计算这个最大总得分。
示例:
假设有 3 堆石子:[1, 2, 3]。
- 一种合并顺序:先合并前两堆
1和2,得到新堆3,得分 =(1+2)^3 = 27。现在石子堆为[3, 3]。再合并这两堆,得分 =(3+3)^3 = 216。总得分 =27 + 216 = 243。 - 另一种顺序:先合并后两堆
2和3,得分 =(2+3)^3 = 125。现在石子堆为[1, 5]。再合并,得分 =(1+5)^3 = 216。总得分 =125 + 216 = 341。
所以,最大总得分为341。
问题分析与思路
这是一个典型的区间动态规划(Interval DP)问题,因为涉及对数组的一个连续区间进行合并操作,最终状态是整个区间合并为一堆。
关键观察:
- 合并过程与区间划分:无论合并顺序如何,最后一次合并一定是将某个左区间合并成一堆的石子,与某个右区间合并成一堆的石子,再进行合并。因此,对于区间
[l, r],我们可以枚举最后一次合并的分界点k(l ≤ k < r),表示先将[l, k]合并成一堆,再将[k+1, r]合并成一堆,最后将这两堆合并。 - 区间状态:定义
dp[l][r]为将区间[l, r]内的石子合并成一堆后,所能获得的最大总得分(注意:这个得分只包括区间内部合并的得分,不包括后续与其他区间合并的得分)。 - 状态转移:
- 对于区间
[l, r],如果l == r,那么只有一堆石子,不需要合并,得分为 0:dp[l][r] = 0。 - 如果
l < r,我们需要枚举最后一次合并的分界点k:- 先合并
[l, k]得到一堆,其石子总数为sum(l, k),合并过程中的最大得分为dp[l][k]。 - 再合并
[k+1, r]得到一堆,其石子总数为sum(k+1, r),合并过程中的最大得分为dp[k+1][r]。 - 最后将这两堆合并,得分 =
(sum(l, k) + sum(k+1, r))^3,实际上就是(sum(l, r))^3。 - 因此,总得分 =
dp[l][k] + dp[k+1][r] + (sum(l, r))^3。
- 先合并
- 我们选择所有分界点
k中,使得总得分最大的那个。
- 对于区间
- 区间石子数量和:为了快速计算任意区间
[l, r]的石子总数,我们可以预先计算前缀和数组prefix,其中prefix[i]表示前i堆石子数量之和(通常prefix[0] = 0)。那么sum(l, r) = prefix[r+1] - prefix[l](如果数组下标从 0 开始)。 - 计算顺序:由于大区间
[l, r]依赖于其内部的更小区间,我们需要按照区间长度从小到大的顺序计算dp。
详细解题步骤
假设石子数组为 stones[0..n-1],长度为 n。
步骤 1:计算前缀和
- 创建数组
prefix,长度为n+1。 prefix[0] = 0。- 对于
i从0到n-1,prefix[i+1] = prefix[i] + stones[i]。 - 这样,区间
[l, r]的石子总数sum(l, r) = prefix[r+1] - prefix[l]。
步骤 2:初始化 DP 表
- 创建一个二维数组
dp,大小为n x n,所有元素初始化为 0。 - 对于所有
l == r,dp[l][r] = 0已经满足。
步骤 3:按区间长度从小到大进行动态规划
- 外层循环:
len从2到n,表示当前处理的区间长度。 - 内层循环:
l从0到n-len,表示区间起点。- 计算区间终点
r = l + len - 1。 - 计算区间石子总数
total = prefix[r+1] - prefix[l]。 - 初始化
dp[l][r]为一个很小的值(例如-inf),因为我们要取最大值。 - 枚举分界点
k从l到r-1:- 当前得分 =
dp[l][k] + dp[k+1][r] + total^3。 - 更新
dp[l][r] = max(dp[l][r], 当前得分)。
- 当前得分 =
- 计算区间终点
步骤 4:得出结果
- 最终答案 =
dp[0][n-1],即将整个数组合并成一堆的最大总得分。
复杂度分析
- 时间复杂度:O(n³)。三重循环:区间长度
O(n),起点O(n),分界点O(n)。 - 空间复杂度:O(n²),用于存储 DP 表。
示例演算
以 stones = [1, 2, 3] 为例,n=3。
步骤 1:前缀和
prefix = [0, 1, 3, 6]。
步骤 2:初始化 DP 表
所有对角线元素为 0。
步骤 3:动态规划
-
长度 len=2:
l=0, r=1:total = prefix[2] - prefix[0] = 3。k=0:得分 =dp[0][0] + dp[1][1] + 3³ = 0 + 0 + 27 = 27。dp[0][1] = 27。
l=1, r=2:total = prefix[3] - prefix[1] = 5。k=1:得分 =dp[1][1] + dp[2][2] + 5³ = 0 + 0 + 125 = 125。dp[1][2] = 125。
-
长度 len=3:
l=0, r=2:total = prefix[3] - prefix[0] = 6。k=0:得分 =dp[0][0] + dp[1][2] + 6³ = 0 + 125 + 216 = 341。k=1:得分 =dp[0][1] + dp[2][2] + 6³ = 27 + 0 + 216 = 243。- 取最大值:
dp[0][2] = 341。
步骤 4:结果
dp[0][2] = 341,与示例一致。
关键点总结
- 立方得分的影响:因为得分是立方增长,合并大堆的奖励非常高,所以策略倾向于尽早合并出较大的堆,以便后续合并获得更高得分。这与最小成本问题(通常倾向于平衡合并)不同。
- 区间DP的经典框架:枚举最后一个合并的分界点,将区间分成左右两个子区间,分别求解后再合并。
- 前缀和优化:快速计算区间和,避免每次重复计算。
通过以上步骤,你可以解决这类“合并相邻石子堆,得分与合并数量和立方相关,求最大总得分”的问题。该问题很好地展示了区间动态规划在处理合并类最优顺序问题上的通用性和灵活性。