动态编程与蛮力编程有何不同


19

当我遇到以下引用时,我正在阅读动态编程

动态编程算法将研究解决问题的所有可能方法,并选择最佳解决方案。因此,我们可以将动态编程粗略地认为是一种智能的,蛮力的方法,它使我们能够通过所有可能的解决方案来选择最佳方案。如果问题的范围如此之大,以至于可以快速解决所有可能的解决方案,那么动态编程可确保找到最佳解决方案

给出了以下示例

例如,假设您必须在高峰时段在给定的城市中尽快从A点到达B点。动态规划算法将调查整个交通报告,调查您可能会走的所有可能的道路组合,然后才告诉您哪种方式最快。当然,您可能需要等待一段时间才能完成算法,然后才能开始驾驶。您将采用的路径将是最快的路径(假设外部环境没有任何变化)

蛮力在决定最佳解决方案之前,正在尝试所有可能的解决方案。

如果动态编程在选择最佳解决方案之前也要通过所有可能的解决方案,那么它与Brute Force 有何不同,我看到的唯一区别是动态编程考虑了其他因素(在这种情况下为交通状况)。

我正确地说动态编程是蛮力方法的子集吗?


1
交通状况是一条红鲱鱼。您可以在任何算法中考虑它们。
Yuval Filmus 2014年


您的第一句未定义动态编程。
reinierpost 2014年

@reinierpost好吧,它试图到达那里intelligent, brute force,但随后忘记描述“智能”部分
Izkata 2014年

@Izkata通过这种推理,每种算法都是“智能蛮力”(无论如何都是矛盾的)。
拉斐尔

Answers:


17

动态编程算法将研究解决问题的所有可能方法,并选择最佳解决方案。

这句话是完全错误的。

动态编程递归确实(经常)考虑根据某种方案将给定问题实例拆分为较小实例的所有可能方法。但是,它不会将所有局部问题的所有解决方案相互结合并选择最佳方案-它仅组合最佳局部解决方案(并从中选择最佳方案)。

这样就可以为原始问题提供最佳解决方案,这一事实并非无关紧要,实际上仅适用于某些问题。即那些满足Bellman最优性原理的(经常引用的最可疑,最易被误解的“定义”之一)。有关方面的更多想法,请参见此处

作为一个具体的例子,考虑具有完整单位权重的完整图K n上的Bellman-Ford算法:它只考虑长度为1和2(即Θ n 2多)的路径,因为使用一条边的路径都是最优的。但也有无穷多的解决方案,如果你不约束允许的最大边数,仍然» ñ - 1 如果您允许每个节点仅使用一次,则很多。显然,Bellman-Ford是一种动态编程算法,它不会执行暴力搜索。ķñΘñ2ñ-1个


“此声明是完全错误的” -对其进行修复
nmclean 2014年

4
@nmclean我在Wikipedia上与算法相关的文章的编辑工作并不愉快,所以没有。我宁愿在这里花时间。
拉斐尔

我碰碰运气,编辑了这篇文章。希望现在少错了。
C4stor 2014年

9

动态编程很聪明,因为它可以重用计算,而蛮力则不会。假设要解决f(6),则需要解决两个都调用f(3)的子问题。蛮力方法将计算f(3)两次,从而浪费精力,而动态编程将调用一次,保存结果,以防将来的计算需要使用它。在许多问题中,动态将蛮力的指数复杂度提高到多项式复杂度。


9
这就是备忘录,这只是DP使用的许多技巧之一。
Ben Voigt 2014年

4
具有记忆力的蛮力仍然低效;只有DP重复提供的其他结构/修剪才能使备忘录得到回报。
拉斐尔

3
我对动态编程一无所知,但我可以肯定,除了将缓存添加到蛮力算法之外,它还有更多的功能。我认为动态编程避免了通过对问题空间进行细分,为每个小细分找到最佳解决方案,然后将它们组合以创建总体最佳解决方案来测试所有可能的组合。(它可以递归地进行此操作,细分细分。)仅当您可以以允许这样的解决方案组合并仍然获得总体最优的方式表达问题时,此方法才有效。
乔纳森·哈特利2014年

1
这个答案实际上是非常准确的。我建议阅读诸如Cormen等人的教科书:“算法简介”以了解有关动态编程的更多信息,这本书的章节相当不错。简而言之,高效的动态编程利用了您要解决的(优化)问题的两个属性:可以从较小子问题的最优解中构造出最佳解决方案,而较小子问题的总数实际上是小。然后,您可以自底向上构建所有子问题解决方案,从而以内存为代价加快计算速度。
MRA 2014年

或更简单地说:如果您知道如何使用Pascal三角形计算二项式系数,那么您将了解动态编程所需的全部知识。
MRA 2014年

3

Wikipedia文章可能试图做出的区分是三种算法之间的区别:

  1. 遍历所有可能解决方案的算法,选择最佳解决方案。

  2. 选择遍历所有可能解的子集的算法,以使最佳解属于该子集。

  3. 遍历所有可能解的子集的算法,而不能保证最优解属于该子集。

前两种算法产生最佳解决方案,而第三种类型旨在产生“良好”解决方案而不是最佳解决方案。我认为,前两种之间的区别不是很明确。

首先,让我在最短路径的背景下为所有三种算法给出简单的例子(您给出的例子)。

  1. 尝试所有可能的路径。这就是蛮力

  2. 尝试所有可能的路径,并跟踪到目前为止的最小解决方案。只要您正在构建的当前路径比到目前为止的最小解决方案昂贵,就放弃它,然后选择另一个(我们假设距离是逐段计算的)。这称为修剪

  3. 查看地图,考虑一些路径,然后从中选择最佳路径。这是针对人而不是计算机的算法。

这些示例相当粗糙,也许无法描绘出非常准确的图景。在许多情况下,例如在计算机国际象棋中,修剪至关重要。如果您好奇,请查找A *算法,该算法实际上用于最短路径。

动态编程是一种用于显着加速蛮力算法的技术。但是,以这种方式思考会有些误导。这是一种用于解决优化问题的算法技术。您可以在动态编程的上下文中实现修剪。

ŤŤŤ+1个Ť


然后,在不进行全面处理的情况下将候选人从考虑中删除。例如,找到具有最小总和的非负数集合,您实际上不必完全对每个集合求和,只需要等到总和超过当前的最佳值即可。这与修剪相似但正交。将这两个想法结合起来,就产生了“分支约束”,解决了复杂性降低的问题,并用来证明修剪的合理性。
Ben Voigt 2014年

0

动态编程比暴力编程要快得多。蛮力可能要花费指数时间,而动态编程通常要快得多。

蛮力的比喻是一个非常松散的比喻。动态编程并不是让您采用所需的任何蛮力算法并使之高效的魔咒。


5
这是结果,而不是解释。
拉斐尔

-2

这很简单。动态编程是一种“搜索策略”,它使用其他因素来缩小搜索范围。如果在搜索空间无解,动态规划(通常)通过做搜索空间的每一个元素进行搜索。但这并不意味着这是一种蛮力搜索。


“如果搜索空间中没有解决方案,则动态编程(通常)将在搜索空间的每个元素中进行搜索。” -错误,请参阅我的答案。
拉斐尔

-2

关于动态编程是智能蛮力的说法是正确的,但是用这种措辞很难理解。动态编程的重点通常是解决问题,然后以智能方式将其分解为较小的部分。完成此操作后,您将使用蛮力求解每个小片段,然后再次使用蛮力将这些片段组合成最终解决方案。因此,尽管您可以肯定地说动态编程是一种蛮力解决方案,但诀窍在于您如何使用这种蛮力。


1
“您将使用蛮力解决每个小问题” –错误。通常,您将递归使用相同的方法。
FrankW 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.