为了获得有效的算法,必须了解一些解体的基本思想和方法。对于很多问题,只要仔细分析了数据对象后,相应的处理方法就有了;对于有些问题则不然。然而,作为探寻问题求解思路的基本思想和方法,对于任何算法设计都是有用的。
1 穷举法
穷举法亦称作枚举法。它的基本思想是,首先根据求解问题的部分条件确定答案的大致范围,即列举出解的所有可能的情况;然后在此范围内对所有可能的情况逐一验证,若某个情况经过验证符合问题条件则为一个解,若全部情况验证后均不符合问题条件则问题无解,从而得出求解问题的完整解。
例如,要找出200~500之间的所有素数,只要对这个范围内的每一个数逐个用素数的定义去判断就行了。
穷举法的特点是算法简单,但是有时运算量大、效率较低。在可以确定解的取值范围,但一时又找不到更好的算法时,就可以使用穷举法求解。
2 迭代法
迭代法的基本思想是,由一个量的原值求出它的新值,不断地再用新值代替原值求出他的下一个新值,直到得到满意的解。新值和原值之间存在一定的关系,这种关系可以用一个公式来表示,称为迭代公式。
迭代法主要用于那些很难用或者无法用解析法求解的一类计算问题,如高次方程和超越方程等,使得复杂问题的求解过程,转化为相对简单的迭代算式的重复执行过程,用数值方法求出问题的近似解。
- 迭代求解算法的基本方法
使用迭代法构造这一类问题求解算法的基本方法是,先确定一个收敛性能好(即收敛速度快)的迭代公式,选取解的一个近似值(即迭代初值)和解的精度要求(即允许的最大误差范围),然后用循环处理实现迭代过程,终止循环的条件是前后两次得到的近似值之差的绝对值小于解的精度要求,并认为最后一次得到的近似解为问题的解。这种方法称作逼近迭代,如著名的牛顿迭代法就是这种逼近迭代方法。
此外,精度值的计算也可以使用迭代法。例如计算 s = 1 +2 +3 +…+1000,可选取迭代公式s +i ->s 和 迭代初值0(即0->s),当i分别取1,2,3…1000时重复计算迭代公式,最后一次便可以求出s的精确值。
3 递推法
递推法是从前面的一些量推出后面的一些量的一种方法,它从已知的初始条件出发,逐次推出所需要求解的各中间结果和最终结果。递推过程往往表现为迭代,即由一些量的原值推出他的新值,不断的用新值替代原值推出下一个新值,直到推出最终结果,新值和原值之间的关系用递推公式表示。
例如Fibonacci数列存在递推关系:
F(1) = 1, F(2) = 2, F(n) = F(n-1) + F(2) (n>=2)
4 递归法
如果一个过程直接或间接的调用它自身,则称该过程是递归的;直接调用自身称作直接递归,间接调用自身称作间接递归。递归是构造算法的一种基本方法,它将一个复杂问题归结为若干个较为简单的问题,然后将这些较为简单的问题进一步归结为更简单的问题,这个过程一直进行下去直到归结为最简单的问题时为止。这个最简单的问题即为递归终止条件,也称作递归出口。
著名的汉诺(Hanoi)塔问题的求解算法就是递归法的典型运用。
- 递归和递推是既有区别又有联系的两个概念
递推是从已知初始条件出发逐次推出最后所求的值;而递归则是从函数本身出发,逐次上溯调用其本身求解过程直到递归出口,然后再从里向外倒推回来得到最终的值。
一般来说,一个递推算法总可以转换为一个递归算法。对于同一问题所设计的递归算法往往要比相应的非递归算法(如递推算法)付出更多的执行时间代价和更多的辅助存储空间开销。
5 回溯法
回溯法是算法设计中的一种基本策略,回溯法是一种优选搜索法,又称为试探法,按优选条件向前搜索,以达到目标,但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术称为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
在那些涉及寻找到一组解的问题或者满足某些约束条件的最优解的问题中,许多都可以使用回溯法求解。例如,在国际象棋棋盘上的骑士周游问题和走迷宫问题,都是使用回溯法进行的。
-
基本思想
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。(其实回溯法就是对隐式图的深度优先搜索算法)。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。 -
用回溯法解题的一般步骤
(1)针对所给问题,确定问题的解空间:
首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展搜索规则
(3)以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
6 贪婪法
贪婪法又称贪心算法,它是通过一系列的选择来得到问题的一个解。贪婪法在每一步所做出的选择,都是在当前状态下看来是最好的选择即贪婪选择,并希望通过每次所作的贪婪选择导致最终结果是求解问题的一个最优解。换句话说,贪婪法并不从整体最优伤进行考虑,它做出的选择只是在某种意义上的局部最优选择,但希望算法得到的最终结果也是整体的。
贪心算法不是对所有问题都能得到最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
- 贪心算法的基本思路
(1)建立数学模型来描述问题。
(2)把求解的问题分成若干个子问题。
(3)对每一子问题求解,得到子问题的局部最优解。
(4)把子问题的解局部最优解合成原来解问题的一个解。
7 分治法
在计算机科学中,分治法是一种很重要的算法,字面上的解释是“分而治之”,就是在求解一个复杂问题时,尽可能的把这个问题分解成若干较小的子问题,在找出各个较小的问题的解之后再组合成为整个问题的解,这就是所谓的分治法。
使用分治法时,往往要按问题的输入规模来衡量问题的大小,当要求解问题的输入贵哦相当大时,应选择适当策略将输入划分成若干子集合得到一组子问题,在求解出各子问题的解之后用适当的方法把他们合并成整个问题的解,分治法并应用成功。
- 分治法的基本步骤
(1) step1 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
(2) step2 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
(3)step3 合并:将各个子问题的解合并为原问题的解。 - 可使用分治法求解的一些经典问题
(1)二分搜索
(2)大整数乘法
(3)Strassen矩阵乘法
(4)棋盘覆盖
(5)合并排序
(6)快速排序
(7)线性时间选择
(8)最接近点对问题
(9)循环赛日程表
(10)汉诺塔
8 动态规划
-
基本概念
动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划。 -
基本思想与策略
基本思想与分治法类似,也是将待求解的问题分解成若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是原始问题的解。
由于动态规划解决的问题有多重叠子问题这个特点,为减少重复计算,对每个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。 -
与分治法最大的区别
适合于动态规划求解的问题,经分解后得到的子问题往往不是互相独立的(即下一子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解) -
适用的情况
能采用动态规划求解的问题一般要具有三个性质:
(1)最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
(2)无后效性:即某一阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
(3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能多次被使用到。(该性质并不是动态规划的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)