动态规划的本质

Posted 涛歌依旧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划的本质相关的知识,希望对你有一定的参考价值。

     我们先来看一个问题:

     a, b, c, n都为正整数,非负整数x, y, z满足ax + by + cz = n,  求min{x + y + z}

     直观的算法是:枚举出x, y, z后, 求min{x + y + z}. 然而,这不是最佳算法。看完本文后,可以用动态规划来解决这个问题。

     

      在介绍动态规划前,我们先来看T公司的一道笔试题目:

     学过排列组合的人应该会做,直接计算:C(12,5) - C(6,3)*C(6,2)

     结果是:492


     有的朋友可能忘记了排列组合,那怎么办呢?可以考虑用机械式的办法来做。我们来找规律,如下图:

动态规划的本质

      设点X到点Y的方法数为f(X,Y),  则有:

      f(M, B) = 1

      f(N, B) = 1

      f(E, B) = f(M, B) = 1

      f(C, B) = f(M, B) +  f(N, B) = 2

      f(D, B) = f(E, B) +  f(C, B) = 3

      

     以点B为(0,0)原点,a[i][j]为点(i,j)走到点B的方法数,很容易得出递推公式:

a[i][j] = a[i][j-1] + a[i-1][j]

     其中i和j都要大于0,至于i或j为0的边界条件,则一目了然。另外,要注意图中P是特殊的点。在笔试现场,如果用如上递推公式,做出这个题目,最多只需要3分钟。


     当问题规模变大后,根据递推公式去计算,对人来说是很麻烦的,但对计算机而言,最适合搞这些有规律的计算了。下面,让计算机来计算:

package main
import "fmt"
func main() { a := [6][8]int {}; for j := 1; j < 8; j++ { a[0][j] = 1 // first row }
for i := 1; i < 6; i++{ a[i][0] = 1 // first column }
// B point a[0][0] = 0 for i := 1; i < 6; i++ { for j := 1; j < 8; j++ { a[i][j] = a[i-1][j] + a[i][j-1] if i == 2 && j == 4 { a[i][j] = 0 // P point } } }
fmt.Println(a[6-1][8-1]) // A point}

      结果是:492


     到此为止,并没有感受到动态规划(Dynamic Programming),那什么是动态规划呢?动态规划,是求解决策最优化的过程,在经济、军事、自动化等领域,都有广泛应用。动态规划的本质就是递推,然而,在有的动态规划问题中,递推并不明显,需要花心思去构建递推关系。


    最后,我们来看下文章开头的问题,动态规划的递推公式为:f(n) = min{f(n-a)+1,  f(n-b) + 1,  f(n-c) + 1},其中,f(n)为n规模下的min{x + y + z},另外,也要注意边界条件。

     动态规划几乎是笔试面试的必考内容,对于求职者而言,需要多训练一下动态规划的思维,找找感觉。关于动态规划的内容,先聊到这里。


以上是关于动态规划的本质的主要内容,如果未能解决你的问题,请参考以下文章

动态规划的实现及关键点

动态规划的本质

详细实例说明+典型案例实现 对动态规划法进行全面分析 | C++

最短路(Floyd算法的动态规划本质)- HDU 2544

DP(动态规划)的本质以及基础优化

DP(动态规划)的本质以及基础优化