【问题标题】:Dynamic programming: Do I have overlapping sub-problems?动态规划:我有重叠的子问题吗?
【发布时间】: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 到达,因此我们可以一举标记它们,而无需重新计算路径。

这就是为什么我认为我的整体问题可以通过动态规划解决。

问题

  1. 我的算法/问题是动态规划的吗?为什么,为什么不呢?
  2. 如果不是,我可以使它成为动态编程吗?如果可以,如何?

【问题讨论】:

    标签: algorithm recursion dynamic-programming


    【解决方案1】:

    是的,这肯定是一个动态规划问题。这实际上是最简单/最基本的动态规划问题——在有向无环图中找到从起始节点可到达的所有节点(在您的情况下为多个起始节点)。您可以使用深度优先搜索或广度优先搜索来解决它。

    它符合这样的定义:

    优化结构?是的,我可以从单元格 x 到达的单元格是 x 加上我可以从 x 的较小邻居到达的单元格的并集。

    重叠子问题?是的,x 的两个邻居可以共享同一个较小的邻居。

    为了使您发布的算法成为动态规划算法,您只需要记住这样的子问题:

    function Step(cellNr):
        foreach neighborNr in neighbors_of(cellNr):
            if array_value(neighborNr) < array_value(cellNr) AND cell_is_not_marked(neighborNr):
                mark_cell(neighborNr)
                Step(neighborNr)
    Step(centerNr)
    

    请注意,这也会将您的算法从指数时间更改为线性时间,并且它是深度优先搜索

    【讨论】:

    • 我的教授说深度优先或广度优先搜索不会被认为是动态规划。他还说(对于单个搜索)子问题没有重叠,因为我们仍然需要检查每个子问题。我倾向于同意他的一次搜索(例如,橙色 9)(我想我不同意你对同一个较小邻居的推理)。我的论点是,没有针对单个搜索的动态规划,但存在针对整个问题的动态规划(如我的示例中所示)。你怎么看?你有参考资料吗?
    • @Make42 如果你说的是真的,那么我很抱歉你的教授错了......但是你的教授可能知道什么是动态编程,什么不是,因此,您可能误解了他所说的内容或适用的上下文。例如,当应用于树时,DFS 是 BFS 不是动态编程,但当应用于 DAG 时它们是动态编程,因为那是子问题重叠的时候。我认为我的解释很清楚,我不需要任何臭名昭著的参考资料。无论如何,您不应该通过计算随机说出一种或另一种方式的互联网用户的数量来决定什么是正确的。
    • @Make42 但是请注意,您发布的 算法 不是动态编程算法,因为您没有记住重叠的子问题。
    • “我认为我的解释很清楚,我不需要任何臭名昭著的参考资料。”我没有冒犯的意思。当我要求参考时,我在考虑发表科学论文,这样我就可以在我的论文中引用它。
    • “你没有记住重叠的子问题”——但这只是我描述的实现的一个问题,对吧?如果我只使用 memoization,这个问题可以通过动态编程来解决,对吧?
    猜你喜欢
    • 2015-03-24
    • 2018-06-11
    • 1970-01-01
    • 2021-02-06
    • 2011-10-17
    • 2012-04-09
    • 2021-02-03
    相关资源
    最近更新 更多