动态规划是一种解决最优化问题的方法,动态规划最大的特点是变化多端,解题方法不是按照一定套路来的。
动态规划一般是能分阶段的问题,可以把大问题转化为小问题,充分利用计算机重复处理问题的特点,把这个问题解决掉。并且动态规划中的变量都是有一定含义的,每个变量都有它所包含的意思,比如:在最长上升子序列这个题中,dp[n]代表了以第n个数结尾的最长子序列的长度。最重要的是动态规划问题要有状态转移方程,这个方程不一定是数学公式,有时候是前后之间的某种关系,一般能够推出公式的题都是比较简单的,难得是找不到一个公式。
动态规划有两个原理,最优化原理和无后效性原理,最优化原理指的是一个阶段的最优解要能导致全局的最优。无后效性原理是当前的最优解确定了,不会再受到其他变化的影响,只与推出它来的状态转移方程有关。
做了很多动态规划题,感觉这种题的核心代码都是循环结构,一般是两重循环,还有三重的。毕竟动态规划是要不断重复计算嘛。
动态规划的一般解题步骤:
1。。分阶段
2。。确定变量的状态,其实我感觉分阶段和确定变量状态没有谁先谁后,有时候是一起想出来的。
3。。找出状态转移方程(不一定是公式)。
4。。确定边界条件。。因为状态转移一般是公式,所有要有结束条件。
动态规划中一种题叫做背包问题。
有三种基础背包问题 :01背包,完全背包,多重背包,
还有一些复杂了一些的背包问题:混合了前面三种背包的背包问题,分组背包,有两个价值的背包,背包方案数问题。
01背包
n个物品放在容量为v的背包里,第i个物品的价值是c[i],体积是w[i]。每件物品只能拿一次。
这就是01背包,红色字体是它和其他基础背包问题的区别。
背包问题一般都有“套路”,也就是相同背包问题大部分的思路代码差不多。
dp[i][j]表示前i个物品放在容量为j的背包里的最大价值。
比如01背包就是两重循环
for int i=1......n
for int j=n.....w[i]
循环里面就是最关键的状态转移方程。
完全背包
n个物品放在容量为v的背包里,第i个物品的价值是c[i],体积是w[i]。每件物品可以拿无限次。
也是两重循环。
for int i=1......n
for int j=w[i].....n
多重背包
n个物品放在容量为v的背包里,第i个物品的价值是c[i],体积是w[i]。每件物品可以拿有限次。
还是两重循环,不过在里面有次数的限制,可以再加一层循环,或者设置一个计算物品次数控制变量。
这两重循环和多重背包一样。
剩下的背包问题都是在这三种背包基础上的变形,只要掌握了这三种背包,其他的背包仔细思考一下也能解决。
动态规划问题可以用滚动数组的方法节省空间,动态规划问题中,尤其是背包问题 ,有很多都是用前一状态的变量推出后一状态的变量,这就可以用滚动数组的方法来节省空间。就是二维数组可以用一维数组来代替,因为另外一维本来就是记录状态的作用。
二进制思想,在多重背包问题中可能要用到,每个数都可以用多个2的n次方来表示,比如26=2^4+2^3+2^1.这样就可以把一个数变成多个数,把多重背包的一个物品变成01背包的多个物品。就可以按照01背包的思想做题了。
在动态规划中有很多题可以用递归函数做,也可以用递推公式加双重循环做,一般数据量大的用递推公式,小的可以用递归函数,有些很多并且要处理多组数据的也可以加上预处理,记忆化搜索什么的。
在动态规划中特殊问题可以用二分法和贪吃算法来做,就是正在学习这部分,二分法是求最大值的最小值,最小值的最大值问题。贪吃是只考虑局部最优,不考虑全局最优,可以减少一层循环。