您如何确定适合动态编程的问题?


19

最近我一直在阅读动态编程。希望从零开始的人那里听到消息,现在他擅长于识别和解决DP问题。我正在努力将这些问题识别为DP并制定简洁的解决方案。

我已经解决了大多数初学者DP问题和MIT资源等

Answers:


17

我来自物理学背景,因此来自许多数学领域。通过找到归纳证明的相似点,我发现容易发现的问题非常适合递归/动态编程解决方案。

通过归纳证明,您可以分为两个部分:

  • 您证明如果迭代N满足某些条件,则迭代N + 1也适用
  • 您证明迭代1是正确的

在递归编程/动态编程中:

  • 您确定退出条件(例如,对迭代1的解决方案进行硬连接)
  • 给定迭代N-1的解,就可以计算迭代N的解

因此,正如其他人回答的那样,这是经验和提示的问题,但是您可以重用其他技能来指导自己。在那之后,您需要始终拥有我提到的两个部分:如果不这样做,那么它将不起作用。

例如,要生成集合的所有排列:

  • 退出条件:如果只有一个元素,则将其返回
  • 递归:一组N个项的排列是通过选择每个元素并将元素与通过除去元素而获得的子集的所有N-1组(许多)排列组合而获得的N个排列。

8

大多数动态编程问题都可以通过记忆来解决。记忆化通常更直观,更容易编写。您可能会发现,根据记忆而不是DP进行思考很有帮助。

通常更容易断定问题是否适合记忆化(步骤与Slivvz的答案相同,但我认为思维上的转变要短一些)。但是,一旦通过备注解决了问题,就可以检查备注缓存的填充方式,然后按顺序填充它,而无需递归...这会将您的算法更改为动态编程算法。

TL; DR; 版本:您可能会发现在记忆方面更容易理解动态编程。

另请参见StackOverflow:动态编程和备注:自下而上与自上而下的方法


4

动态编程在定义上与两件事有关:

  1. 最佳子结构
    较大的解决方案可以从较小的解决方案中获取;解决不是双向的。

  2. 子问题重叠
    小解决方案将被重用多次。如果子问题根本不重叠,那么您就不会从DP /记忆化中受益。你所拥有的是而治之。

解决DP问题的一般方法是:

  • 编写有效的简单递归或迭代版本。

  • 请注意,该函数正在执行多余的工作。

  • 找到一种方法来避免做这些多余的工作,通常是通过记忆。


从理论上讲,所有这些都是正确的。国际海事组织(IMO)需要做一些练习才能更加熟悉快速识别:)
2014年

2

我从来没有实现过一个动态编程求解器-我的背景是应用数学/物理/数值计算,而不是CS-直到几年前我开始做Euler项目问题。的DP-可解决的问题存在(例如,76158161242,但还有更多)被证明是我最喜欢的一种。当这将是一种有用的技术时,您肯定会做得更好:基本上寻找看起来可以通过某种递归,分而治之的方法解决的问题,其中还可以应对需要解决的爆炸式增长问题通过识别重复出现的子问题并重用先前计算的结果来进行探索;至关重要的一步是能够识别要记住的最小状态向量,以及可以删除哪些不相关的“历史”。

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.