动态规划部分知识点总结
动态规划部分知识点总结
动态规划与贪心算法之间的关系:
关于动态规划,很多东西都与贪心算法类似,都是解决多决策问题的一种方法。(多阶段决策问题:一类问题的求解过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策,并影响到下一个阶段的决策。
多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果。)
贪心算法是通过某种贪心标准在每一步的选择中都采取当前状态下最好或最优的选择,希望得到的结果是最好或最优的解法。这种策略是一种很简洁的方法,对许多问题它能产生整体最优解,但不能保证总是有效,因为它不是对所有问题都能得到整体最优解。(贪心算法通过以局部最优的求解方式试图获取整体问题的最优解,但局部最优有时候并非可以达到整体最优。)
动态规划相对贪心算法要复杂得多,贪心算法不能保证问题的最优性,但是使用动态规划的目的就是得到最优解,所以动态规划通过枚举所有可能的最优解来进行选取以保证得到整体最优解,其中包含了贪心算法的思想。(所有的贪心都可以通过动态规划来实现。)(动态规划实际上就是一种排除重复计算的算法,更具体的说,动态规划就是用空间换取时间。(动态规划的记忆化搜索(记忆已算过的数据,从而排除重复计算,换取时间。)))
动态规划的几个概念:
阶段:据空间顺序或时间顺序对问题的求解划分阶段。
状态:描述事物的性质,不同事物有不同的性质,因而用不同的状态来刻画。对问题的求解状态的描述是分阶段的。
决策:根据题意要求,对每个阶段所做出的某种选择性操作。
状态转移方程:用数学公式描述与阶段相关的状态间的演变规律。
动态规划的一般步骤:
一、判断问题是否可以使用动态规划(判断问题是否具有最优子结构的性质)
二、分阶段:把问题据时间或空间顺序对问题的求解划分阶段(分为若干个子问题)。
三、建立状态转移方程(递推关系式)
四、找出边界条件。
五、将已知边界值带入方程。
六、递推求解。
动态规划与递推的关系:
上面提到的对于动态规划很重要的一步是建立状态转移方程(递推关系式),其实很多简单的动态规划问题就是规律性递推问题,或正推或逆推。这里让我想到了斐波拉契数,这个递推式为f(b)=f(b-1)+f(b-2)。用到该问题的一个例题就让我想到了楼梯问题以及蜜蜂过蜂房问题,都是用这种方法来解决。
对于状态转移方程(递推关系式),很明显很多时候都用到了递推思想,因此在解决问题时一定要注意其是否存在规律性,是否可以用递推这样一种思想方法来解决问题。
部分零碎知识点:
二维空间到一维空间的转化:
另外上次还提到了二维问题如何转化为一维数轴问题(当时是投影的方式),现在我们也可以考虑对二维平面空间进行压缩(记录平面区间坐标点的方法)。
我们可以用dx[]={-1,0,1,0},dy[]={0,1,0,-1}来表示对应的上下左右四个方向。
64位整型数在不同编译器中的不同规定:
对于提交OJ的问题:OJ的编译环境不同,使用的一些定义方式也可能存在偏差,例如HDU上使用windows编译器,在定义长整型时以如下方式定义:__int64 temp;输出时:printf("%I64d\n",temp);这其实就是我们在使用GCC编译器里的longlong类型,只是由于编译系统的问题,我们定义的方式要有所差距。
以下我们可以看一下资料上的解释:在C/C++中,64位整型一直是一种没有确定规范的数据类型。现今主流的编译器中,对64为整型的支持也是标准不一,形态各异。一般来说,64位整型的定义方式有long long和__int64两种(VC还支持_int64),而输出到标准输出方式有printf(“%lld”,a),printf(“%I64d”,a),和cout << a三种方式。
数组清零的快速方法:
memset(a,0,sizeof(a));(数据量大时远比for循环快的多)但是如果有n个数组需要清零,memset只能一个一个清零,但是循环可以一次性清零。当n>2时,循环比memset好。当然使用memset()函数时必须要注明头文件:#include< cstring >或#include< cstdlib >。