【发布时间】:2019-03-16 09:48:18
【问题描述】:
我的算法
假设我有一个二维实数数组。我从这个数组中的一个特定单元格开始,其中有一个特别大的数字。我想标记哪些其他单元格应该属于提到的起始单元格。规则是这样的:如果我找到从起始单元格走到另一个单元格的方法,则另一个单元格属于起始单元格。我只被允许上或下走一个牢房。我只被允许从一个数字较大的牢房走到一个数字较小的牢房。这是我从中心 9 开始的示例
我的伪算法是
function Step(cellNr):
foreach neighborNr in neighbors_of(cellNr):
if array_value(neighborNr) < array_value(cellNr):
mark_cell(neighborNr)
Step(neighborNr)
Step(centerNr)
现在是第二个方面,例如,我不仅对一个起始单元格执行此操作,而且对多个起始单元格执行此操作
动态编程
我研究了dynamic programming,发现需要满足两个条件才能应用动态规划:
- 子问题需要重叠
- 子问题需要有最优的子结构
“[动态规划]是指通过递归方式将复杂问题分解为更简单的子问题来简化[...]如果可以通过将问题分解为子问题然后递归查找来最佳解决问题子问题的最优解,则称其具有最优子结构。[...] 问题必须具有两个关键属性才能使动态规划适用:最优子结构和重叠子问题。如果一个问题可以通过组合非重叠子问题的最优解来解决,则该策略称为“分而治之”。这就是为什么合并排序和快速排序不属于动态规划问题。最优子结构意味着给定优化问题的解可以通过其子问题的最优解的组合来获得。这种最优子结构通常通过递归来描述。[...]重叠子问题意味着子问题的空间必须很小,即任何解决问题的递归算法都应该一遍又一遍地解决相同的子问题,而不是产生新的子问题。"Wikipedia
我想知道我的算法是否是动态编程。它绝对是递归的,并且在子结构中似乎是最优的。不过,我开始怀疑重叠的子结构。有一个斐波那契数的例子,但在我看来,关键方面是可以存储递归算法的中间结果。对于我的算法,无法存储中间结果 - 至少不能存储单个起始单元格的一次运行。然而,当我考虑整个问题时,有许多起始单元格,我们看到一些区域是相连的:
假设我们从左侧图像中的橙色 9 开始,沿着绿色路径向下直到到达蓝色 5。从那里我们还可以到达蓝色 3 和蓝色 2。我们完成了左侧的算法橙色 9.
现在我们转向右图中下方的橙色 8。我们从这个 8 开始,沿着绿色路径向上到达绿色 6。从那里我们到达蓝色 5。我们已经从之前的计算中知道(从左图中的橙色 9),蓝色 3 和蓝色 2可以从蓝色 5 到达,因此我们可以一举标记它们,而无需重新计算路径。
这就是为什么我认为我的整体问题可以通过动态规划解决。
问题
- 我的算法/问题是动态规划的吗?为什么,为什么不呢?
- 如果不是,我可以使它成为动态编程吗?如果可以,如何?
【问题讨论】:
标签: algorithm recursion dynamic-programming