本文总结了常用的5种算法设计办法和理念.
最优化问题(optimization problem)
每个最优化问题都包含一组限制条件(constraint)和一个优化函数(optimization function), 符合限制条件的问题求解方案可称为可行解(feasible solution), 能够
使得优化函数取得最佳值的可行解称为"最优解" (optimal solution)
【方法一】贪心法(greedy method)
算法思想:在贪婪算法中采用逐步构造最优解的方法。在每个阶段,都作出一个看上去最优的决策(在一定的准则下)。决策一旦作出,就不可再更改。作出贪婪决策
的依据称为贪婪准则(greedy criterion)
典型例子:最短路径、找零钱、货箱装船、拓扑排序、最小生成树
【方法二】分而治之算法
算法思想:分而治之方法与软件设计的模块化方法非常相似。为了解决一个大的问题,可以如下做:
a. 它分成两个或多个更小的问题;
b. 分别解决每个小问题;
c. 把各个小问题的解答组合起来,即可得出原问题的答案。
小问题通常与原问题相似,可以递归地使用分而治之策略来解决。
典型例子:找出伪币、金块问题、矩阵分块相乘、残缺棋盘、归并排序、快速排序、距离最近的点对
【方法三】动态规划(dynamic programming)
算法思想:和贪婪算法一样,在动态规划中,可将一个问题的解决方案视为一系列决策的结果。不用的是,在贪婪算法中,每采用一个次贪婪准则做出一个不可撤回
的决策,而在动态规划中,还要考察每个最优决策序列中是否包含一个最优子序列。动态规划方法采用最优原则(principle of optimality)来建立用于计算最优解的递归式。
所谓最优原则即不管前面的策略如何,此后的决策必须是基于当前状态(由上一次决策产生)的最优决策。由于对于有些问题的某些递归式来说并不一定能保证最优原则,
因此在求解问题时有必要对它进行验证。若不能保持最优原则,则不可应用动态规划方法。
个人观点: 动态规划的数学表现是递归、排列组合,在递归过程中会出现重复计算问题,为了解决这个开销,使用二维表格保存已计算出的结果,以便复用!
典型例子:最短路径、0/1背包问题、矩阵乘法链、元件折叠
【回溯法】
寻找问题的解的一种可靠的方法是首先列出所有候选解,然后依次检查每一个,在检查完所有或部分候选解后,即可找到所需要的解。理论上,当候选解数量
有限并且通过检查所有或部分候选解能够得到所需解时,上述方法是可行的。
算法思想:回溯(backtracking)是一种系统地搜索问题解答的方法。为了实现回溯,首先需要为问题定义一个解空间(solution space),这个空间必须至少包含
问题的一个解(可能是最优的)。在迷宫老鼠问题中,我们可以定义一个包含从入口到出口的所有路径的解空间;在具有n 个对象的0 / 1背包问题中解空间的一个
合理选择是2^n个长度为n 的0 / 1向量的集合,这个集合表示了将0或1分配给x的所有可能方法。
回溯方法的步骤如下:
1) 定义一个解空间,它包含问题的解。
2) 用适于搜索的方式组织该空间。
3) 用深度优先法搜索该空间,利用限界函数避免移动到不可能产生解的子空间。
回溯算法的一个有趣的特性是在搜索执行的同时产生解空间。
【分支界定】
类似于回溯法,分枝定界法在搜索解空间时,也经常使用树形结构来组织解空间。然而与回溯法不同的是,回溯算法使用深度优先方法搜索树结构,而分枝定界
一般用宽度优先或最小耗费方法来搜索这些树。
算法思想:分枝定界(branch and bound)是另一种系统地搜索解空间的方法,它与回溯法的主要区别在于对E-节点的扩充方式。每个活节点有且仅有一次机会变成
E-节点。当一个节点变为E-节点时,则生成从该节点移动一步即可到达的所有新节点。在生成的节点中,抛弃那些不可能导出(最优)可行解的节点,其余节点加入活
节点表,然后从表中选择一个节点作为下一个E-节点。从活节点表中取出所选择的节点并进行扩充,直到找到解或活动表为空,扩充过程才结束。