确定动态编程的子问题


39

我已经多次使用动态编程技术,但是今天有一个朋友问我如何定义子问题,我意识到我无法提供客观的正式答案。您如何正式定义要使用动态编程解决的问题的子问题?


似乎所有现有答案(截至2019年4月)都不够好,尤其是对于初学者而言。我会推荐其他网站上的教程。
Apass.Jack

Answers:


35

动态编程的原理是自上而下(即递归)思考,但自下而上地解决。因此,设计DP的一个好的策略是递归地描述问题并以这种方式生成子问题。


14
我声称这是唯一的策略。
JeffE 2012年

2
@JeffE是的,我在教算法课时阅读并使用了您的笔记,它很有效。Quote:“动态不是要填写表格。它是关于智能递归的!”

2
我对如何教DP的理解受到@JeffE的注释的强烈影响:)
Suresh

3
也可以将自顶向下的递归过程自动转换为动态编程算法。当您要返回时,将答案存储在哈希表中。在每个呼叫开始时,检查答案是否已在哈希表中,如果已经存在,则立即返回。这个想法使许多算法变得容易。例如,使用这样的表,尝试的递归算法将自动在DAWG上工作。通过在调用开始时将哨兵值存储在表中,即使在DFA上,相同的算法也可以工作。BDD上的算法变得非常容易递归指定。
Jules 2012年

1
最后但并非最不重要的一点是,它可以具有巨大的性能优势。例如,传统的自下而上的子集和算法可以计算大量不需要的表条目。使用此方法,仅将计算必要的表条目。
朱尔斯2012年

4

正如@Suresh所指出的,一旦您知道自己的问题可以通过DP解决(即,它表现出最优的子结构和重叠的子问题),您可能会想到分而治之的递归解决方案。

O(1)

因此,考虑分而治之的解决方案将为您提供有关特定问题可能存在子问题的见解。


1
“最佳子结构”(无论意味着什么)可能不足以解决DP问题。“重叠子问题”当然不是必需的。
拉斐尔

1
最佳子结构和重叠的问题都可以通过DP来有效解决。当然,仅最佳的子结构不足以解决DP的溶解性。但是,如果您没有重叠的子问题,则可以用相同的代价通过普通的分而治之来解决问题:实际上,DP超越分而治之的优势是,在递归树中遇到每个子问题时,只需解决一次。
马西莫卡法罗

1
这不是我的提法:您可以在Cormen,Leiserson,Rivest和Stein的“算法简介”中找到它,也可以在许多其他有关算法的教科书中找到它。
Massimo Cafaro 2012年

1
乔普(Jup),大多数人至少部分错了。如果您提出合适的问题,我很乐意详述。
拉斐尔

1
我不确定我是否正确理解您的最后评论。为了表明这种表征是错误的(不能部分错误:是正确的还是错误的),您可以简单地作为一个反例来说明这个问题,该问题既不显示最佳子结构,也不显示重叠的子问题,但是适用于多项式DP解。但是请注意,在这种情况下,这意味着比普通的分而治之要好得多的解决方案。
Massimo Cafaro 2012年

2

我的经验是找到一种方法,“借助存储已枚举的有用值来减少多余的枚举”。顺便说一句,动态编程在ICPC(国际大学生编程竞赛)中确实很受欢迎。在实践了几个ICPC问题之后,任何人都可以对DP有自己的感觉。

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.