1 分治法
定义:
求解一个复杂问题可以将其分解成若干子问题,子问题在分解成更小的问题,直到可以直接求解为止。
前提:
- 问题能够按照某种方法分解为若干个规模较小、相互独立且与原问题类型相同的问题;
- 子问题足够小时可以直接求解;
- 能够将子问题的解组合成原问题的解。
算法框架:
SolutionType DandC(ProblemType P){ ProblemType P1,P2,P3,...Pn; if(Small(P)) return S(P); //子问题P足够小,直接求解 else{ Divide(P1,P2,P3,...Pn); //将问题P分解为子问题P1,P2,...Pn Return Combine(DandC(P1),DandC(P2),...,DandC(Pk)); //求解子问题,并合并解 }}
相关算法:
2 贪心法
定义:
贪心法是求解最优化问题的一种设计策略。贪心法通过分步决策来求解问题。在对问题求解时,总是做出在当前这一步看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
最优化问题:问题给出某些约束条件,满足这些约束条件的解称为可行解;为了衡量可行解的好坏,问题还给出了目标函数,使目标函数取最大(小)值的可行解称为最优解。
贪心法在每一步上用作决策依据的选择准则被称为最优量度标准或贪心准则,这种量度标准通常只考虑局部最优性。
贪心法基本要素:
最优度量标准:所谓贪心法的最优度量标准,是指可以根据该度量标准,实行多步决策进行求解,虽然在该度量标准下所做的这些选择都是局部最优的,但最终得到的解却是全局最优的。选择最优度量标准是使用贪心法求解问题的核心问题。贪心算法每步做出的选择可以依赖以前做出的选择,但绝不依赖将来的选择,也不依赖子问题的解。也正是如此,贪心法的特征是自顶向下,一步一步地做出贪心决策。
最优子结构:当一个问题的最优解中包含了自问题的最优解时,则称该问题具有最优子结构特性。一个可用贪心法求解的问题往往呈现最优子结构性质。
并不是所有具有最优子结构特性的问题,都可以有幸的找到最优量度标准,此时可以考虑采用求解。
算法模板:
SolutionType Greedy(SType a[],int n){ SolutionType solution = null; //初始解向量不含任何分量 for(int i = 0;i
相关算法:
- 一般背包问题
- 最小代价生成树问题(、)
3 动态规划法
动态规划法:与类似,动态规划法也是一种求解最优化问题的算法设计策略。它也采取分布决策的方法。但与贪心法不同的是,动态规划法每一步决策依赖子问题的解。直观上,为了在某一步做出决策,需要先求若干子问题,这就使得动态规划法是自底向上的。
按照多部决策方法,一个问题的活动过程可以分成若干阶段,每个阶段可能包含一个或多个状态。多部决策求解方法就是从初始状态开始做出每个阶段的决策,形成一个决策序列,该决策序列也成为策略。对于每一个决策序列,可以用一个数值函数(目标函数)衡量该策略的优劣。问题求解的目标是获取最优决策序列(最优策略)。
动态规划法基本要素:
最优子结构特性:和贪心法相同。
重叠子问题:动态规划法的子问题往往是重叠的,如果采用与分治法类似的直接递归会非常费时。为了避免重复计算,动态规划法一般采用自底向上的方式进行计算,并保存已经求解的子问题的值。当这些子最优解值被重复引用时,无需重新计算。
设计动态规划法步骤:
- 刻画最优解的结构特性;
- 递归定义最优解值;
- 自底向上方式计算最优解值;
- 根据计算得到的信息构造一个最优解。
相关算法:
4 回溯法和分枝限界法
定义:
使用剪枝函数的深度优先生成状态空间树中的节点的求解方法称为回溯法;广度优先生成结点,并使用剪枝函数的方法称为分枝限界法。
- 显示约束和解空间:规定每个分量xi取值的约束条件称为显式约束。对给定的一个问题,显示约束规定了所有可能的元组,他们组成问题的候选解集,被称为该问题实例的解空间。
- 隐式约束和判定函数:隐式约束给出了判定一个候选解是否为可行解的条件。一般需要从问题描述的隐式约束出发,设计一个判定函数,程序根据判定函数判断一个解是否为可行解。
- 最优解和目标函数:目标函数,也称代价函数,用来衡量每个可行解的优劣。使目标函数取得最大(小)值的可行解为问题的最优解。
- 剪枝函数:为了提高搜索效率,在搜索过程中使用约束函数,可以避免无谓地搜索那些已知不含答案状态的子树。如果是最优化问题,还可以使用限界函数剪去那些不可能含有最优解的子树。约束函数和限界函数目的相同,都是为了剪去不必要搜索的子树,减少问题求解所需实际生成的状态结点数,他们统称为剪枝函数。
条件:
- 它的解具有n-y元组的形式;
- 问题提供显式约束来确定状态空间树,并提供隐式约束来判定可行解;
- 能设计有效的约束函数缩小检索空间。
回溯法算法框架:
Void RBacktrack(int k){ for(每个x[k],使得x[k]∈T[x[0],...,x[k-1]&&B(x[0],...x[k]){ if(x[o],x[1],...,x[k]是一个可行解) 输出(x[o],x[1],...,x[k]); RBacktrack(k+1); }}
回溯法相关算法:
- 哈密顿环问题
分枝限界法相关算法:
- 带时限作业排序