目录
一、什么是DP
DP是用来解决多阶段问题的优化算法思想。用我自己的话简单来说就是,一次计算多次利用。
在计算某一个最终状态的最优解时,可以分解为计算子问题的最优解,把子问题的最优解累加起来就是最终解。不是很理解的话,可以思考一下斐波那契数列的计算就是这个原理。
那么什么时候可以使用DP呢?它可以用于解决具有以下结构特征的问题,也就是说有以下特征的题目可以考虑使用DP
-
重叠子问题
-
最优子结构问题
这就是DP的特征
二、DP特征
1、重叠子问题
什么是重叠子问题呢?
-
子问题就是大问题的小问题,但是要满足其操作步骤一样。就好比吃蛋糕,你可以一口吃掉反复咀嚼(这就是解决大问题),你也可以一小口一小口慢慢咬(这就是大问题的小问题,操作步骤都是反复咀嚼)。
-
那重叠就是重复的意思,即我要想计算大问题就必须重复计算小问题,也就是小问题要被计算多次
满足上面的就是重叠子问题
2、最优子结构
子问题明白了,那我相信子结构你也应该明白了吧。
那最优呢?我们已经知道大问题的解是依靠于小问题得出来的结果,如果满足当每一个子问题结果都是最优解时,大问题的解既是最优解的话,那么就满足最优子结构这一说法。
三、DP的编程方法
DP无非就是大问题和小问题之间的关系,那么实现DP就只需要按照这个思路来即可。这里有两种方法:
自顶向下:先从大问题如手,逐步深入到小问题
自底向上:从小问题逐步累积得到大问题的解
自顶向下
由大问题到小问题,我们一般会选择递归,而DP作为优化算法,为了解决上面提到的”小问题要被计算多次“,所以每次计算完成我们都需要将结果直接记录,以保证下次计算时可以直接获取,从而到达优化的效果。
下面以斐波那契(走楼梯)为例:
int arr[N]; //用于记录数据
int solve(int n)
{
if (n == 1 || n == 2)return 1; //到底了,及最小的子问题
if (arr[n] != 0)return arr[n]; //该子问题已有最优解,直接返回
arr[n] = arr[n - 1] + arr[n - 2]; //到达该台阶只有俩种方式,要么是一次一台阶要么是一次俩台阶
return arr[n];
}
自底向上
由小问题到大问题,即递推,也需要记录来减少计算次数。
下面以斐波那契(走楼梯)为例:
int arr[N]; //用于记录数据
int solve(int n)
{
arr[1] = 1; //起始的两个台阶都只需要一步
arr[2] = 2;
for (int i = 3; i <= n; i++)
{
arr[i] += arr[i - 1] + arr[i - 2]; //到达该台阶只有俩种方式,要么是一次一台阶要么是一次俩台阶
}
return arr[n];
}
总结
小白尝试写博客,写的不是很好,希望看见这篇文章的大佬们能够慷慨的给予一些意见。
之所以尝试写博客,是因为听从师兄的建议尝试通过这种方式来加强自己的理解和记忆。