分治法
把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并(子问题须相互独立,且与原问题形式相同)。
设计思想:
将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。
分治策略:算法设计策略叫做分治法
、对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
分治法适用的情况
分治法所能解决的问题一般具有以下几个特征:
1、该问题的规模缩小到一定的程度就可以容易地解决
2、该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
3、利用该问题分解出的子问题的解可以合并为该问题的解(不满足该条件,可考虑用贪心法或动态规划法);
4、该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
分治法的基本步骤
分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题
合并:将各个子问题的解合并为原问题的解。
一般的算法设计模式:
Divide-and-Conquer(P)
1、if |P|≤n0 then return(ADHOC(P)) // 当P的规模不超过n0时直接用算法ADHOC(P)求解
2、将P分解为较小的子问题 P1 ,P2 ,…,Pk
3、递归解各子问题Pi
for i←1 to k
do yi ← Divide-and-Conquer(Pi)
4、合并各子问题解,得到问题P的最终解
T ← MERGE(y1,y2,…,yk)
return(T)
说明:
P: 表示问题
|P|:表示问题P的规模
n0: 为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。
ADHOC(P):分治法中的基本子算法,用于直接解小规模的问题P。
分治法类似于数学归纳法,找到解决本问题的求解方程公式,然后根据方程公式设计递归程序:
1、先找到最小问题规模时的求解方法
2、然后考虑随问题规模增大时的求解方法
3、找到求解的递归函数式后(各种规模或因子),设计递归程序。
分治法的复杂性分析
一个分治法将规模为n的问题分成k个规模为n/m的子问题去解。设分解阀值n0=1,且adhoc解规模为1的问题耗费1个单位时间。再设将原问题分解为k个子问题以及用merge将k个子问题的解合并为原问题的解需用f(n)个单位时间。用T(n)表示该分治法解规模为|P|=n的问题所需的计算时间,则有:
T(n)= k T(n/m)+f(n)
通过迭代法求得方程的解:
递归方程及其解只给出n等于m的方幂时T(n)的值,但是如果认为T(n)足够平滑,那么由n等于m的方幂时T(n)的值可以估计T(n)的增长速度。通常假定T(n)是单调上升的,当mi≤n<mi+1
时,T(mi)≤T(n)<T(mi+1)
。
分治法求解的一些经典问题
二分搜索
大整数乘法
Strassen矩阵乘法
棋盘覆盖
合并排序
快速排序
傅立叶变换(快速傅立叶变换)
线性时间选择
最接近点对问题
循环赛日程表
汉诺塔
动态划分算法
动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)
每次决策依赖于当前状态,又随即引起状态的转移。
一个决策序列就是在变化的状态中产生出来的,
所以,这种多阶段最优化决策解决问题的过程就称为动态规划。
基本思想、策略
基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
由于动态规划解决的问题多数有重叠子问题(分解后得到的子问题往往不是互相独立的—即下一子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解,且有重叠子问题)这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。
动态规划求解的问题的一般要具有3个特性:
1、问题具有最优子结构,即满足最优化原理。
2、无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响(某状态以后的过程不会影响以前的状态,只与当前状态有关)。
3、有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。
动态规划求解的基本步骤:
初始状态→│决策1│→│决策2│→…→│决策n│→结束状态
1、划分阶段:
按照问题的时间或空间特征,把问题分为若干个阶段。注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。
2、确定状态和状态变量:
将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来,且状态的选择要满足无后效性。
3、确定决策、状态转移方程:
因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。
4、寻找边界条件:
给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
一般,只要解决问题的阶段、状态和状态转移决策确定了,就可以写出状态转移方程(包括边界条件)
实际算法实现的设计步骤:
1、分析最优解的性质,并刻画其结构特征。
2、递归的定义最优解。
3、以自底向上或自顶向下的记忆化方式(备忘录法)计算出最优值
4、根据计算最优值时得到的信息,构造问题的最优解
算法实现的说明
动态规划求解问题,最重要的就是确定动态规划三要素:
1、问题的阶段
2、每个阶段的状态
3、从前一个阶段转化到后一个阶段之间的递推关系。
递推关系必须是从次小的问题开始到较大的问题之间的转化,动态规划往往可以用递归程序来实现,递推可以充分利用前面保存的子问题的解来减少重复计算(动态规划算法的核心之处)。
确定了动态规划的这三要素,整个求解过程就可以用一个最优决策表来描述,最优决策表是一个二维表:
1、行表示决策的阶段
2、列表示问题状态,表格需要填写的数据一般对应此问题的在某个阶段某个状态下的最优值(如最短路径,最长公共子序列,最大价值等)
3、填表的过程就是根据递推关系,从1行1列开始,以行或者列优先的顺序,依次填写表格,
最后根据整个表格的数据通过简单的取舍或者运算求得问题的最优解。
f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}
动态规划算法基本框架
复制代码
代码
for(j=1; j<=m; j=j+1) // 第一个阶段
xn[j] = 初始值;
for(i=n-1; i>=1; i=i-1)// 其他n-1个阶段
for(j=1; j>=f(i); j=j+1)// f(i)与i有关的表达式
//通过决策保留那些有可能达到最优的局部解,丢弃其他局部解
xi[j] = max(或min){g(xi-1[j1:j2]), ……, g(xi-1[jk:jk+1])};
t = g(x1[j1:j2]); // 由子问题的最优解求解整个问题的最优解的方案
贪心算法
在对问题求解时,总是做出在当前看来是最好的选择(不从整体最优上加以考虑,仅是在某种意义上的局部最优解)
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性
无后效性:即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
贪心策略适用的前提是:
用贪心算法只能通过解局部最优解的策略来达到全局最优解,要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断
贪心算法的基本思路:
1、建立数学模型来描述问题。
2、把求解的问题分成若干个子问题。
3、对每一子问题求解,得到子问题的局部最优解。
4、把子问题的解局部最优解合成原来解问题的一个解。
贪心算法的实现框架
从问题的某一初始解出发;
while (能朝给定总目标前进一步){
利用可行的决策,求出可行解的一个解元素;
}
由所有解元素组合成问题的一个可行解;
回溯法:选优搜索法(深度优先搜索),在解空间树中回溯寻找所有解
基本思想
回溯法深度优先搜索解空间树中活结点的所有可行子结点被遍历后才被从栈中弹出找出满足约束条件的所有解
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
回溯法的搜索策略
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。
1、若用回溯法求问题的所有解时:要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
2、而若使用回溯法求任一个解时:只要搜索到问题的一个解就可以结束。
回溯法一般步骤:
1、确定问题的解空间:
首先应明确定义问题的解空间,问题的解空间应至少包含问题的一个(最优)解。
2、确定结点的扩展搜索规则
3、以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
分支限界法:广度优先策略或者最小耗费(最大效益)优先,搜索一个解或者最优解
分支限界法的求解目标是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优
分支限界法以广度优先或最小消耗优先搜索解空间树、解空间树每个结点只有一次成为活结点的机会找出满足约束条件的一个解或特定意义下的最优解
分支搜索算法
所谓“分支”就是采用广度优先的策略,依次搜索E-结点的所有分支,也就是所有相邻结点,抛弃不满足约束条件的结点,其余结点加入活结点表。然后从表中选择一个结点作为下一个E-结点,继续搜索。
选择下一个E-结点的方式不同,则会有几种不同的分支搜索方式。
1、FIFO搜索
2、LIFO搜索
3、优先队列式搜索
分支限界法的搜索策略:
分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。问题的解空间树是表示问题解空间的一棵有序树,常见的有子集树和排列树。
在扩展结点处,先生成其所有的儿子结点(分支),然后再从当前的活结点表中选择下一个扩展对点。为了有效地选择下一扩展结点,以加速搜索的进程,在每一活结点处(每一个活结点只有一次机会成为扩展结点。活结点一旦成为扩展结点,就一次性产生其所有儿子结点。在这些儿子结点中,那些导致不可行解或导致非最优解的儿子结点被舍弃,其余儿子结点被子加入活结点表中),计算一个函数值(限界),并根据这些已计算出的函数值,从当前活结点表中选择一个最有利的结点作为扩展结点,使搜索朝着解空间树上有最优解的分支推进,以便尽快地找出一个最优解
回溯法和分支限界法的一些区别:
1、方法对解空间树的搜索方式:
回溯法以深度优先的方式搜索解空间树T, 分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树T
2、存储结点的常用数据结构
3、结点存储特性