环形游乐场的最优游览路线问题
字数 2823 2025-12-10 03:42:55

好的,我注意到你已经了解了许多区间动态规划的题目。现在,我为你讲解一个尚未出现在列表中的经典问题。

环形游乐场的最优游览路线问题

题目描述:

假设有一个环形的游乐场,上面有 n 个景点,按顺时针顺序编号为 0n-1。每个景点 i 都有一个 娱乐值 v[i](可以是正数、负数或零)。你将从任意一个景点出发,顺时针游览,目标是选择一段 连续的景点区间(长度至少为1),使得这段区间内景点的娱乐值之和 最大

但是,由于是环形结构,你选择的区间可以跨越 n-10 这个边界。例如,如果 n=5,你选择了景点 [4, 0, 1],这也是合法的连续区间。

请你计算,在这个环形游乐场中,能够获得的最大娱乐值总和。

形式化输入:

  • 一个整数数组 v,长度为 n
    输出:
  • 一个整数,表示最大可能的连续子数组和(允许跨越环形边界)。

解题过程循序渐进讲解

这个问题是经典“最大子数组和”(Kadane算法)的环形变种。我们先从简单情况开始思考。

步骤 1:回顾基础问题(线性数组)

在一条直线排列的景点(线性数组)中,求最大子数组和有一个著名的 Kadane算法,其核心思想是动态规划。

定义状态:
dp[i] 表示 以第 i 个元素结尾的 所有连续子数组中,能获得的最大和。

状态转移方程:
对于当前元素 v[i],你有两个选择:

  1. 独自开始一段新的子数组:和为 v[i]
  2. 接在前一个元素结尾的最大子数组后面:和为 dp[i-1] + v[i]
    为了最大化,我们取两者中较大的一个:
    dp[i] = max(v[i], dp[i-1] + v[i])

最终,答案就是所有 dp[i] 中的最大值。
这个算法的时间复杂度是 O(n),空间复杂度可以优化到 O(1),因为只需要记录前一个 dp 值。

步骤 2:思考环形带来的挑战

在环形结构中,最大和子数组可能有两种情况:

  1. 情况A:不跨越边界。 这就退化成了步骤1中的线性Kadane问题。
  2. 情况B:跨越边界。 例如选择了 [i, i+1, ..., n-1, 0, ..., j],其中 j < i

关键洞察:
情况B(跨越边界) 等价于从整个数组的总和中,挖掉中间一段不选的子数组。而被挖掉的这部分,正是原数组中一个连续的、和最小 的子数组(因为我们要让剩下的部分和最大)。

所以,环形数组的最大子数组和可以转化为:
max(最大子数组和(不跨越), 数组总和 - 最小子数组和(不跨越))

但这里有一个 边界条件:如果整个数组所有数都是负数,那么“数组总和 - 最小子数组和”会得到0(因为最小子数组和就是所有负数之和,总和减它等于0)。但题目要求子数组至少有一个元素,所以此时答案应该是最大的那个负数,而不是0。而“最大子数组和(不跨越)”在这种情况下恰好就是最大的那个负数。

因此,最终的逻辑是:

  1. 分别用Kadane算法求出线性情况下的 最大子数组和 max_linear最小子数组和 min_linear
  2. 计算数组总和 total_sum
  3. 环形最大和候选值为 max_linear(情况A)和 total_sum - min_linear(情况B)。
  4. 特殊情况:如果 max_linear < 0(即所有数为负),则直接返回 max_linear。否则,返回 max(max_linear, total_sum - min_linear)

为什么特殊情况判断是 max_linear < 0
因为当所有数为负时,min_linear 等于 total_sum(所有负数加起来)。那么 total_sum - min_linear = 0,但这对应了选择一个“空子数组”,不符合题目“至少一个元素”的要求。而此时的 max_linear 就是那个绝对值最小的负数,是合法答案。

步骤 3:算法设计与举例

算法流程:

  1. 初始化:
    cur_max = v[0], best_max = v[0] (用于找最大和)
    cur_min = v[0], best_min = v[0] (用于找最小和)
    total = v[0]
  2. i = 1 遍历到 n-1
    a. 更新最大和
    cur_max = max(v[i], cur_max + v[i])
    best_max = max(best_max, cur_max)
    b. 更新最小和
    cur_min = min(v[i], cur_min + v[i])
    best_min = min(best_min, cur_min)
    c. 累加总和:total += v[i]
  3. 得到 best_max(即 max_linear),best_min(即 min_linear),total
  4. 如果 best_max < 0,返回 best_max
    否则,返回 max(best_max, total - best_min)

举例说明:
假设 v = [1, -2, 3, -1, 2]

  • 线性最大和 best_max: 子数组 [3, -1, 2],和为4。
  • 线性最小和 best_min: 子数组 [-2],和为 -2。
  • 总和 total: 1 + (-2) + 3 + (-1) + 2 = 3。
  • 情况A(不跨越): 4
  • 情况B(跨越): total - best_min = 3 - (-2) = 5,对应的子数组是 [3, -1, 2, 1](即舍弃了 -2)。
  • 最终结果:max(4, 5) = 5

再举一个全负数的例子:v = [-3, -5, -2]

  • best_max = -2 (子数组 [-2]
  • best_min = -10 (子数组 [-3, -5, -2]
  • total = -10
  • 因为 best_max < 0,所以直接返回 -2。如果套用公式 max(-2, -10 - (-10)=0) 会得到0,这是错误的。

步骤 4:复杂度分析与总结

  • 时间复杂度O(n),我们只需要一次遍历数组,同时计算最大和、最小和以及总和。
  • 空间复杂度O(1),只使用了几个变量。

核心思想总结
将环形问题巧妙地转化为两个线性问题(求最大子数组和、最小子数组和)的组合。通过考虑“跨越边界”等价于“从总和中扣除中间一段”,而为了使剩余部分最大,扣除的部分(中间段)必须最小。最后处理全负数的边界情况即可。

这个解法优雅且高效,是处理环形结构上最大子数组和问题的标准方法。

好的,我注意到你已经了解了许多区间动态规划的题目。现在,我为你讲解一个尚未出现在列表中的经典问题。 环形游乐场的最优游览路线问题 题目描述: 假设有一个环形的游乐场,上面有 n 个景点,按顺时针顺序编号为 0 到 n-1 。每个景点 i 都有一个 娱乐值 v[i] (可以是正数、负数或零)。你将从任意一个景点出发,顺时针游览,目标是选择一段 连续的景点区间 (长度至少为1),使得这段区间内景点的娱乐值之和 最大 。 但是,由于是环形结构,你选择的区间可以跨越 n-1 和 0 这个边界。例如,如果 n=5 ,你选择了景点 [4, 0, 1] ,这也是合法的连续区间。 请你计算,在这个环形游乐场中,能够获得的最大娱乐值总和。 形式化输入: 一个整数数组 v ,长度为 n 。 输出: 一个整数,表示最大可能的连续子数组和(允许跨越环形边界)。 解题过程循序渐进讲解 这个问题是经典“最大子数组和”(Kadane算法)的环形变种。我们先从简单情况开始思考。 步骤 1:回顾基础问题(线性数组) 在一条直线排列的景点(线性数组)中,求最大子数组和有一个著名的 Kadane算法 ,其核心思想是动态规划。 定义状态: dp[i] 表示 以第 i 个元素结尾的 所有连续子数组中,能获得的最大和。 状态转移方程: 对于当前元素 v[i] ,你有两个选择: 独自开始一段新的子数组:和为 v[i] 。 接在前一个元素结尾的最大子数组后面:和为 dp[i-1] + v[i] 。 为了最大化,我们取两者中较大的一个: dp[i] = max(v[i], dp[i-1] + v[i]) 最终,答案就是所有 dp[i] 中的最大值。 这个算法的时间复杂度是 O(n) ,空间复杂度可以优化到 O(1) ,因为只需要记录前一个 dp 值。 步骤 2:思考环形带来的挑战 在环形结构中,最大和子数组可能有两种情况: 情况A:不跨越边界 。 这就退化成了步骤1中的线性Kadane问题。 情况B:跨越边界 。 例如选择了 [i, i+1, ..., n-1, 0, ..., j] ,其中 j < i 。 关键洞察: 情况B(跨越边界) 等价于从整个数组的总和中, 挖掉中间一段不选的子数组 。而被挖掉的这部分,正是原数组中一个连续的、 和最小 的子数组(因为我们要让剩下的部分和最大)。 所以,环形数组的最大子数组和可以转化为: max(最大子数组和(不跨越), 数组总和 - 最小子数组和(不跨越)) 但这里有一个 边界条件 :如果整个数组所有数都是负数,那么“数组总和 - 最小子数组和”会得到0(因为最小子数组和就是所有负数之和,总和减它等于0)。但题目要求子数组至少有一个元素,所以此时答案应该是最大的那个负数,而不是0。而“最大子数组和(不跨越)”在这种情况下恰好就是最大的那个负数。 因此,最终的逻辑是: 分别用Kadane算法求出线性情况下的 最大子数组和 max_linear 和 最小子数组和 min_linear 。 计算数组总和 total_sum 。 环形最大和候选值为 max_linear (情况A)和 total_sum - min_linear (情况B)。 特殊情况:如果 max_linear < 0 (即所有数为负),则直接返回 max_linear 。否则,返回 max(max_linear, total_sum - min_linear) 。 为什么特殊情况判断是 max_linear < 0 ? 因为当所有数为负时, min_linear 等于 total_sum (所有负数加起来)。那么 total_sum - min_linear = 0 ,但这对应了选择一个“空子数组”,不符合题目“至少一个元素”的要求。而此时的 max_linear 就是那个绝对值最小的负数,是合法答案。 步骤 3:算法设计与举例 算法流程: 初始化: cur_max = v[0] , best_max = v[0] (用于找最大和) cur_min = v[0] , best_min = v[0] (用于找最小和) total = v[0] 从 i = 1 遍历到 n-1 : a. 更新最大和 : cur_max = max(v[i], cur_max + v[i]) best_max = max(best_max, cur_max) b. 更新最小和 : cur_min = min(v[i], cur_min + v[i]) best_min = min(best_min, cur_min) c. 累加总和: total += v[i] 得到 best_max (即 max_linear ), best_min (即 min_linear ), total 。 如果 best_max < 0 ,返回 best_max 。 否则,返回 max(best_max, total - best_min) 。 举例说明: 假设 v = [1, -2, 3, -1, 2] 。 线性最大和 best_max : 子数组 [3, -1, 2] ,和为4。 线性最小和 best_min : 子数组 [-2] ,和为 -2。 总和 total : 1 + (-2) + 3 + (-1) + 2 = 3。 情况A(不跨越): 4 情况B(跨越): total - best_min = 3 - (-2) = 5 ,对应的子数组是 [3, -1, 2, 1] (即舍弃了 -2 )。 最终结果: max(4, 5) = 5 。 再举一个全负数的例子: v = [-3, -5, -2] 。 best_max = -2 (子数组 [-2] ) best_min = -10 (子数组 [-3, -5, -2] ) total = -10 因为 best_max < 0 ,所以直接返回 -2 。如果套用公式 max(-2, -10 - (-10)=0) 会得到0,这是错误的。 步骤 4:复杂度分析与总结 时间复杂度 : O(n) ,我们只需要一次遍历数组,同时计算最大和、最小和以及总和。 空间复杂度 : O(1) ,只使用了几个变量。 核心思想总结 : 将环形问题巧妙地转化为两个线性问题(求最大子数组和、最小子数组和)的组合。通过考虑“跨越边界”等价于“从总和中扣除中间一段”,而为了使剩余部分最大,扣除的部分(中间段)必须最小。最后处理全负数的边界情况即可。 这个解法优雅且高效,是处理环形结构上最大子数组和问题的标准方法。