动态编程与贪婪算法有何不同?

时间:2012-12-04 23:05:14

标签: algorithm dynamic-programming greedy

在我使用Introduction to the Design & Analysis of Algorithms的书中,动态编程据说专注于最优性原则,“任何实例的最佳解决方案优化问题由其子实例的最佳解决方案组成“。

然而,贪心技术专注于扩展部分构建的解决方案,直到您找到完整问题的解决方案。然后说,它必须是“在该步骤中所有可行选择中最好的本地选择”。

既然两者都涉及局部最优,那么它不是另一个的子集吗?

7 个答案:

答案 0 :(得分:44)

动态编程适用于具有以下特性的问题:

  • 重叠的子问题和
  • 最佳子结构。

最佳子结构意味着您可以贪婪地解决子问题并将解决方案结合起来解决更大的问题。 动态编程和贪婪算法之间的区别在于动态编程,存在重叠的子问题,并且使用memoization 解决了这些子问题。 “Memoization”是一种技术,使用子问题的解决方案可以更快地解决其他子问题。

这个答案引起了一些关注,所以我会给出一些例子。

考虑问题“用美元,镍币和便士做出改变”。这是一个贪婪的问题。它展示了最佳的子结构,因为您可以解决美元的数量。然后,求解镍的数量。然后是便士的数量。然后,您可以有效地将解决方案组合到这些子问题中。它并没有真正表现出重叠的子问题,因为解决每个子问题对其他子问题没有多大帮助(可能有点)。

考虑问题“Fibonnaci数字”。它表现出最佳的子结构,因为你可以有效地(通过加法)从F(9)和F(8)求解F(10)。这些子问题重叠,因为它们都共享F(7)。如果你在求解F(8)时记忆F(7)的结果,你可以更快地求解F(9)。

回应关于动态编程与“重新考虑决策”的评论:对于任何线性动态编程算法(如the maximum subarray problem或上述Fibonacci问题)显然不是这样。

基本上,将具有最优子结构的问题想象为有向无环图,其节点表示子问题(其中整个问题由其indegree为零的节点表示),并且其有向边表示子问题之间的依赖性。然后,一个贪婪的问题是一个树(除了root之外的所有节点都有单位indegree)。动态编程问题有一些节点的indegree大于1。这说明了重叠的子问题。

答案 1 :(得分:11)

不同之处在于,动态编程需要您记住较小状态的答案,而贪心算法是本地的,因为所需的所有信息都处于当前状态。当然,还有一些交集。

答案 2 :(得分:9)

关键的区别在于贪婪算法“静态地”构成解决方案,因为解决方案中的每个本地选择都可以最终确定,而无需了解其他本地选择。然而,动态算法为子问题创建了一组可能的解决方案,并且只在考虑了所有子问题时才生成全局问题的单一解决方案。 Wikipedia page on greedy algorithms说得好:

  

贪婪算法所做出的选择可能取决于目前为止做出的选择,而不取决于未来的选择或子问题的所有解决方案。它迭代地使一个接一个的贪婪选择,将每个给定的问题减少为一个较小的问题。换句话说,贪婪算法从不重新考虑其选择。这是与动态编程的主要区别,动态编程是详尽的,并保证找到解决方案。在每个阶段之后,动态编程基于前一阶段做出的所有决策做出决策,并可能重新考虑前一阶段的算法解决方案。

答案 3 :(得分:6)

DP算法使用(对于某些问题) - 大小n问题的最佳解决方案由大小n'<n问题的最优解决方案组成,并使用它来构建解决方案自下而上,从最小的问题到所需的大小。

它非常适合递归的原理(将问题减少到更小的子问题,并递归调用),实际上 - DP解决方案通常表示为递归公式。

贪婪算法正在查看本地点,并在此时对数据做出一些选择。对于一些问题(例如,没有负权重的最短路径) - 这种本地选择将导致最佳解决方案。

两种方法之间差异的一个很好的例子是shortest path problem

  • Dijsktra's Algorithm是一种贪婪的方法(在每一步中,选择当前最小化其路径的节点 - 根据算法的本地状态贪婪地完成选择。)
  • Bellman-Ford algorithm是一个DP解决方案(“放松”所有边缘,有效地减少了问题)

答案 4 :(得分:1)

贪婪的方法:

  1. 贪婪方法专注于扩展部分构建的解决方案。
  2. 它提供了许多结果,例如可行的解决方案。
  3. 效率更高
  4. 动态编程:

    1. 着重于最优性原则。
    2. 它提供了具体的答案。
    3. 效率低下

答案 5 :(得分:0)

DP和贪婪之间的区别是DP会在每个子问题上寻找全局最优,但贪婪只会寻找局部最优。所以,关于这种情况:

假设你正在爬山,你想要尽可能高地攀爬。山上的道路有几个分支,在每个交叉路口你需要决定采取哪个分支,这是这个攀登问题的子问题(目标是相同的,只有起点不同)

对于贪婪的算法,你总是会选择一个看起来更陡峭的算法。这是本地最佳决策,并不保证能够获得最佳结果

对于DP,在每个交叉路口,您应该已经知道每个分支将引导您的最高海拔高度(假设您的评估顺序被反转,也就是从终点到起点),并选择具有最高海拔的那个。这个决定建立在未来子问题的全局最优化的基础上,并且全局最适合这个子问题

答案 6 :(得分:-1)

贪婪和动态解决方案的概念并不相互排斥,我认为这在大多数答案中引起了很多混乱。我相信amit的答案强调最重要的属性:贪婪的解决方案根据本地信息做出决策。因此,贪婪的解决方案可能最终找到本地最优而不是全局优化。 动态解决方案将问题分解为较小的子问题,然后汇总结果以获得更复杂问题的答案。那么 - 问题可能是动态贪婪?答案是 - 是的,这是可能的。一个例子是Dijkstra的算法。对于这个算法,你可以在每个步骤上做出贪婪的选择,然后将问题简化为更简单的子问题。

还有一些不是DP-s的贪婪算法的例子:比如爬山是一种贪婪的算法,不会将问题分解成多个子问题 - 它只能解决一个问题。还有一些不贪婪的DP的例子 - 例如使用memoization计算第n个Fibonacci数并不贪心。

相关问题