动态规划(Dynamic Programming)
dp是什么?
dp是一种编程方法;将一个问题拆成几个子问题,分别求解这些子问题,即可推断出大问题的解。
- 无后效性
"未来与过去无关",这就是无后效性。如果给定某一阶段的状态,则在这一阶段以后过程的发展不受这阶段以前各段状态的影响;
- 有重复的子问题
子问题会被求解多次;
- 最优子结构
大问题的最优解可以由小问题的最优解推出,这个性质叫做“最优子结构性质”;
什么时候可以用dp?
根据以上三个概念,我们如何判断一个问题能否使用dp解决呢?能将大问题拆成几个小问题,且满足无后效性、最优子结构性质
- 计数问题:如用n种资源完成某个方法的数量有多少种;
- 优化:如达成某成目的需要多少钱或者走多少走的问题,这些问题我们在用递归或搜索求解时,因为会枚举所有的可能的路经,当时间复杂度达到如O(2^n)和n的规模很大时,就可以使用dp来进行降维;
dp的通常实现的方法
- Top-down,记忆化递归,从大到小;例如一开始要求解f(10),那f(10)=f(8)+f(9),求解过的会放到内存里(map,array,list等);
- Bottom-up,通常意义上我们定义的DP,从小到大;例如要先求解到dp[1],才能求解dp[2],再能求解dp[3];
dp的典型应用
- Fibonacci sequence (code)
- LCS:最长公共子序列
- Knapsack
- Floyd-Warshall
- Bellmen-Ford