1. 穷举法
基本思想:列举问题的所有可能解,并用约束条件逐一进行判定,找出符合约束条件的解。
穷举法的关键在于问题的可能解的列举和可能解的判别。
例如:凑数问题
2. 递归技术
定义:直接或间接调用自身的过程
递归三要素:
(1)问题形式:返回结果是什么?需要哪些入口参数?
(2)递归规则:问题如何进行分解?
(3)终结条件:什么情况下可以无需套用递归规则直接求解?
3. 分治法
基本思想:待解问题若可以被分解成若干个相互独立的、与原问题同类型的、规模小于原问题的子问题,则可以先求解子问题,再合并子问题的解来得到原问题的解。
设计过程分为三个阶段:(1)整个问题划分为多个子问题;(2)求解各个子问题(递归调用正设计的算法);(3)合并子问题的解,得到原始问题的解。
分析过程:(1)建立递归方程;(2)求解;
递归方程的建立方法:
(1)设输入大小为n,T(n)为时间复杂性;
(2)当n<c,T(n)=θ(1);
(3)Divide阶段的时间复杂性:划分问题为a个子问题;每个子问题大小为n/b;划分时间可直接得到=D(n);
(4)Conquer阶段的时间复杂性:递归调用;Conquer时间=aT(n/b);
(5)Combine阶段的时间复杂性:时间可以直接得到=C(n)。
总之:
T(n)=θ(1) if n<c;
T(n)=aT(n/b)+D(n)+C(n) otherwise
求解递归方程T(n):使用Master定理
目的:求解T(n)=aT(n/b)+f(n)型方程,a>=1,b>0是常数,f(n)是函数。
方法:记住以下三种情况
定理: 假设有递推关系式 T(n) = aT(n/b) + f(n),其中 n 为问题规模,a 为递推的子问题数量,n/b 为每个子问题的规模(假设每个子问题的规模基本一样),f(n) 为递推以外进行的计算工作。
a≥1,b>1为常数,f(n) 为函数,T(n) 为非负整数。则有以下结果:
4. 动态(Dynamic)规划算法
基本思想:动态规划算法常用来求解最优化问题;
其思想是:问题的最优解如果可以由子问题的最优解推导得到,则可以先求解子问题的最优解,在构造原问题的最优解;若子问题有较多的重复出现,则可以自底向上从最终子问题向原问题逐步求解。
优化问题的特点:
优化问题:给定一个代价函数,在解空间中搜索具有最小或最大代价的优化解;
优化问题的特点:(1)可划分为多个子问题,优化解包含子问题的优化解;(2)子问题的解被重复使用
动态规划特点:
(1)把原始问题划分成一系列子问题;
(2)求解每个子问题仅一次,并将其结果保存在一个表中,以后用到时直接存取,不重复计算,节省计算时间–自底向上地计算。
适用范围
一类优化问题:可分为多个相关子问题,子问题的解被重复使用
Dynamic Programming算法的优化条件:
Optimal substructure(优化子结构):当一个问题的优化解包含了子问题的优化解时,就说这个问题具有优化子结构。
Subteties(重叠子问题):在问题的求解过程中,很多子问题的解将被多次使用。
典型:
集合划分问题:存在一个正整数集合S={a1, a2, …, an},将其划分为两个集合,使得划分得到的两个集合中元素和差的绝对值最小。
例如:矩阵连乘、备忘录方法
5. 贪心算法(Greedy算法)
基本思想:通过做出当前看来最优的选择(贪心选择,也就是说贪心算法并不从整体最优考虑,它所做出的选择只是在某种意义上的局部最优选择),将原问题规模缩小,如此反复,之道得到最终解;
贪心算法并非对所有问题都能得到整体最优解。
Greedy算法产生优化解的条件:(1)Greedy-choice-property;(2)Optimal substructure
Greedy选择性:若一个优化问题的全局优化解可以通过局部优化选择得到,则该问题称为具有Greedy选择性。(一个问题是否具有Greedy选择性需证明)
Optimal substructure(优化子结构):当一个问题的优化解包含了子问题的优化解时,就说这个问题具有优化子结构。
基本要素:
(1)贪心选择性质:所求问题的整体最优解可由一系列局部最优解选择得到;动态规划是由子问题的解得到当前问题的解,贪心算法则是由当前局部问题导出子问题;确定一个问题是否具有贪心选择性质,需要证明问题的一个整体最优解是从贪心选择开始的;
(2)最优子结构性质:通过局部最优选择,原问题将被化简为类似的子问题;亦即是说,整体最优解中包含子问题的最优解。
注意:可用Greedy方法时,动态规划方法可能不适用;可用动态规划方法时,Greedy方法可能不适用。
典型:任务选择问题
例如:迪杰斯特拉(Dijkstra)算法用于求解图上的单源点最短路径。
6. 回溯法
回溯法是一种通用性解法,可以看作是带优化的穷举法。
基本思想:在一棵含有问题全部可能解的状态空间树上进行深度优先搜索,解为叶子节点,搜索过程中每到达到一个结点时,判断该结点为根的子树是否含有问题的解,如果不含有问题的解,则放弃该子树的搜索,退回到上层父结点,继续下一步深度优先搜索过程。
在回溯法中,并不是优先构造出整棵状态空间树,再进行搜索,而是在搜索过程中,逐步构造出状态空间树,即边搜索,边构造。
回溯法的使用:
(1).确定问题状态结构;
(2).分析问题状态空间树;
(3).确定深度搜索与回溯规则;
(4).确定解状态判别规则。
子集和问题:
问题:给定由n个不同正数组成的集合w={wi},和正数M,求所有和等于M的自己的集合;
问题状态:可以设想集合中的每个正数都有选取何不选取两种可能,w的一个子集即为一个问题状态,可以表述为对每个元素选取或不选取的一个组合。
问题状态空间树:由空集开始,依次对每个元素进行选取和不选取两种选择,就可以得到W的全部子集,选取过程就可构成一个状态空间树。
按照回溯法思想,从状态树的根结点出发,做深度优先搜索;为便于计算,将w中的整数按从小到大排序;当在某一状态A下依次尝试加入和不加入Wi,若 状态A下的和 + Wi > M,则停止对该结点的搜索;若 状态A下的和 + Wi < M,也可停止对该结点的搜索;
回溯法分析:
(1)一个可以用回溯法求解的问题,通常可以表述为以下形式:对于由n元组(x1,x2,x3...xn)组成的状态空间E={(x1...xn)},给定n元组上的一个约束集D:求E中满足D的全部约束条件的所有n元组。将E中满足D的全部约束条件的一个n元组称为问题的一个解。
7. 限界剪枝法
也称分支定界法。
基本思想:与回溯法相似,也是对状态空间树进行搜索求解,不同的是分支定界法的求解目标是要找到使得某一目标函数极大或极小的一个解结点,即某种意义下的最优解。在算法设计上,不仅通过约束条件来控制搜索路径,还通过目标函数的限界来减少搜索规模;在进行搜索时通常先进行广度拓展,将满足约束条件且不越过目标函数的子结点加入到活结点表中等待搜索;
常见的活结点表:队列式(FIFO)、栈式(LIFO)、优先队列式(PQ)
例如:最小耗费搜索法(15迷问题)