因此,我看了有关Knapsnack问题的视频,该视频可以递归解决,也可以使用动态编程解决。我对动态编程的要旨是,它只不过是字典,列表或我们已经计算出的东西的记录总和,因此我们不必再次进行计算。
这是关于动态编程的全部内容吗?执行记录保存并在必要时使用?
答案 0 :(得分:2)
我们考虑一种动态编程方法来解决问题
简单地说,动态编程有两个方面,它们是自上而下和自下而上的方法。
在自上而下的方法中,我们将尝试编写一个递归解决方案或蛮力解决方案并记住结果,以便在出现类似的子问题时尝试使用该结果,因此它是蛮力+记忆。
在自下而上的方法中,我们将尝试从我们已经知道解决方案的基本案例或非常小的子问题中形成解决方案。我们将通过填充动态编程表来构建针对较大问题的解决方案,该表将映射所有可能的组合并再次提供蛮力模板。
提出与问题的数学关系并确定上述两个属性是具有挑战性的部分。
非正式地,当一个问题需要多次解决相同的子问题时,我们说它有重叠的子问题。
非正式地,当您需要解决大小为n的问题时,可以将该问题分为大小为n'的子问题。所以现在让我们说它有两个阶段,一个阶段是问题n,另一阶段是子问题n'。另外,我们假设您知道大小为n'的最佳解决方案,因此您以某种方式将这些子问题解决方案组合在一起,从而获得了大小为n的解决方案。如果组合解决方案与大小为n的问题的实际最优解相同,则可以肯定地说问题具有最优子结构。
让我们举一个简单的例子来找到第n个斐波那契数,以很好地理解这两个属性。 通常的数学递归关系为
F(n) = F(n-1) + F(n-2)
让我们尝试找出此示例的两个属性。 非正式地讲,为自己理解,取n的值总是很容易的。 令n为3,
F(3) = F(2) + F(1)
我们知道F(0)= 0和F(1)= 1的最优解为基本情况。
F(3)
/ \
/ \
F(2) F(1)
/ \ / \
F(1) F(0) F(0) 0
从上面的递归树中,您可以轻松地发现我们必须多次重新计算F(0)和F(1)。因此它有重叠的子问题。
我们知道斐波那契数列为0 1 1 2 ... 让我们将子树视为
F(2)
/ \
F(1) F(0)
将子问题的最优解与加法运算相结合将为
F(2) = F(1) + F(0)
F(2) = 1 + 0
F(2) = 1
结合子问题解决方案已经为我们提供了针对问题n = 2的实际最佳解决方案,可以从已知的斐波那契数列中予以确认。因此,这个问题也具有最优的子结构。
答案 1 :(得分:1)
来自Wikipedia:“ 动态编程是一种解决复杂问题的方法,将其分解为更简单的子问题的集合,一次解决每个子问题,并使用基于内存的数据结构存储其解决方案(数组,地图等)。“
像递归算法一样,关键是使用高效的数据结构来帮助您解决任务,从而在较小的子问题中解决问题。
因此,简而言之,这实际上是关于有效的记录保持(+ 排序算法 + 智能数据结构)。
答案 2 :(得分:1)
简单来说,我们正在解决一个小的问题(称为子问题),然后将其用于解决更大的问题。
要实现这一目标,我们会记录到现在为止所计算的内容,这些记录可以在下一次使用而不是重新进行计算。