Rod Cutting Problem in Java

2025年5月2日 | 阅读 4 分钟

这是一个著名的优化问题,使用动态规划来获得最大利润——钢管切割问题。给定一根固定长度的钢管,我们想尽可能多地切割它,以便获得最大的收益,因为每种长度的切割片都有不同的价格。这个问题类似于“背包问题”,因为在每一步我们都在决定做什么以最大化利润。

问题陈述

给定

  • 一根长度为 n 的钢管。
  • 一个 数组 prices[],其中 prices[]i 是长度为 i + 1 的钢管切片的價格。

其思想是尽可能地切割钢管以最大化收益,切割钢管的价格由 prices 数组表示。

示例

请看以下示例

prices = [1, 5, 8, 9, 10, 17, 17, 20]

钢管长度 n = 8

通过出售钢管切片,我们可以获得的最大收益是 22。

问题解决方案

为了解决这个问题,我们将

编写递归解决方案以计算最大收益。

相反,优化应用动态规划,以免进行不必要的计算。

动态规划方法

此解决方案具有指数级时间复杂度,因为我们只使用递归,其正确性来自尾递归,它会重复计算相似长度的最大利润。使用动态规划,我们可以通过存储子问题的结果来降低问题复杂度。

动态规划解决方案的步骤

  • 定义一个数组 dp[],其中 dp[i] 将包含用长度为 i 的钢管可以获得的最大利润。
  • 因此,我们可以将 dp[0] = 0 进行初始化,它只是长度为 0 的钢管的收益。
  • 对于从 1 到 n 的每个长度,进行迭代并找到该长度的最大收益。
  • 将结果存储在 dp[] 中,然后对于每个长度 i,考虑所有可能的切割位置来计算最大利润。

让我们用 Java 程序实现上述方法。

文件名:RodCutting.java

输出

 
Maximum profit for rod length 8: 22   

解释

dp[] 数组初始化

  • dp[] 存储长度为 i 的钢管的最大收益,我们创建一个数组。数组的大小为 n + 1,我们可以访问 0 到 n 之间的索引。

填充 dp 数组

  • 如题所述:对于每个钢管长度 i 从 1 到 n,我们通过改变第一个切割 j 从 0 到 n 来找到最大利润。
  • 切割长度 j + 1 的最大利润加上剩余长度为 i - j - 1 的钢管的最大利润在 dp[i] = Math.max(dp[i], prices[j] + dp[i - j - 1]) 中计算。

结果:

  • dp[n] 是长度为 n 的钢管可获得的最大利润的结果。

复杂度分析

时间复杂度:我们有一个 嵌套循环:外层循环运行 n 次(对于每个长度),内层循环最多运行 i 次,所以这是 O(n^2)。

空间复杂度:我们使用 dp[] 数组来存储每个长度的最大收益,其复杂度为 O(n)。

结论

钢管切割问题是一个很好的问题,可以展示通过 动态规划 存储中间结果能有效地降低复杂度。我们还通过构建一个最大利润数组来解决这个问题,该数组是先前解决方案的组合,以及一种获取最大收益的高效算法。

这种动态规划方法可以进一步适应更复杂的情况:它们不仅在约束条件上有所不同(例如,可能会引入额外的约束),而且在定价结构上也有所不同。


下一个主题Java String Encoding