算法设计与分析回溯法.docx
- 文档编号:20123461
- 上传时间:2023-04-25
- 格式:DOCX
- 页数:13
- 大小:113.14KB
算法设计与分析回溯法.docx
《算法设计与分析回溯法.docx》由会员分享,可在线阅读,更多相关《算法设计与分析回溯法.docx(13页珍藏版)》请在冰豆网上搜索。
算法设计与分析回溯法
回溯算法的应用
课程名称:
算法设计与分析
院系:
学生姓名:
学号:
专业班级:
指导教师:
2013年12月27日
回溯算法的应用
摘要:
回溯法是一个既带有系统性又带有跳跃性的的搜索算法。
它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。
算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。
如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。
否则,进入该子树,继续按深度优先的策略进行搜索。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。
回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有可行的子树都已被搜索遍才结束。
而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。
这就是以深度优先的方式系统地搜索问题解的回溯算法,它适用于解决一些类似n皇后问题等求解方案问题,也可以解决一些最优化问题。
在做题时,有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。
回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。
关键词:
回溯法深度优先搜索递归
第1章绪论
1.1回溯算法的背景知识
回溯算法是尝试搜索算法中最为基本的算法,在递归算法中,其存在的意义是在递归知道可解的最小问题后,逐步返回原问题的过程。
实际上是一个类似于枚举的搜索尝试方法,他的主题思想是在搜索尝试的过程中寻找问题的解,当发现不满足条件时就回溯返回,尝试别的路径。
简单的说就是:
从问题的某一种初始状态出发,依次搜寻每一种可能到达的情况,当走到这条路的“尽头”时,回过头到上一个情况,看这个情况是否还有没有走过的路,依次进行下去,直到遍历完所有的情况。
回溯法实际上是一种深度优先搜索的方式。
对于回溯法解决的问题,通常将其解空间组织成图或者树的形式。
对于用回溯法求解的问题,首先要将问题进行适当的转化,得出状态空间树。
这棵树的每条完整路径都代表了一种解的可能。
通过深度优先搜索这棵树,枚举每种可能的解的情况;从而得出结果。
但是,回溯法中通过构造约束函数,可以大大提升程序效率,因为在深度优先搜索的过程中,不断的将每个解与约束函数进行对照从而删除一些不可能的解,这样就不必继续把解的剩余部分列出从而节省部分时间。
1.2回溯法的前景意义
在做题时,有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。
回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。
通过运用回溯法,可以解决很多问题,譬如我们所熟知的“八皇后问题”、“0/1背包问题”,这只是在教学阶段中的运用,在实际运用中回溯法也能起到很大的作用。
回溯法适用于解决难以归纳一般规律解法的问题,其适用范围广,灵活性大,在解一些列举方法的问题时尤其可用。
但是,其缺点也是明显的,即时间复杂度较大;因此在采用时我们应该因情况的不同而做出不同的选择。
第2章回溯算法的理论知识
2.1回溯算法设计过程
(1)确定问题的解空间
应用回溯法解问题时,首先应明确定义问题的解空间。
问题的解空间应至少包含问题的一个(最优)解。
(2)确定结点的扩展规则,如每个皇后在一行中的不同位置移动,而象棋中的马只能走“日”字等。
(3)搜索解空间
回溯算法从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。
这个开始结点就成为一个活结点,同时也成为当前的扩展结点。
在当前的扩展结点处,搜索向纵深方向移至一个新结点。
这个新结点就成为一个新的活结点,并成为当前扩展结点。
如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。
此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。
回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。
2.2回溯算法框架
(1)问题框架
设问题的解是一个n维向量(a1,a2,.....,an),约束条件是ai(i=1,2,3,....,n)之间满足某种条件,记为f(ai)。
(2)非递归回溯框架
inta[n],i;
初始化数组a[];
i=1;
While(i>0(有路可走))and([未到达目标])//还未回溯到头
{if(i>n)//搜索到叶结点
搜索到一个解,输出;
else//正在处理第i个元素
{a[i]第一个可能的值;
while(a[i]在不满足约束条件且在搜索空间内)
a[i]下一个可能的值;
if(a[i]在搜索空间内)
{标识占用的资源;
i=i+1;}//扩展下一个结点
else
{清理所占的状态空间;//回溯
i=i-1;}
}
}
(3)递归算法框架
回溯法是对解空间的深度优先搜索,在一般情况下用递归函数来实现回溯法比较简单,其中i为搜索深度,框架如下:
inta[n];
try(inti)
{if(i>n)
输出结果;
else
for(j=下界;j<=上界;j++)
if(f(j))
{a[i]=j;
...
try(i+1);
回溯前的清理工作(如a[i]置空值等);
}
}
2.3回溯算法的一般性描述
回溯法的一般描述
可用回溯法求解的问题P,通常要能表达为:
对于已知的由n元组(x1,x2,…,xn)组成的一个状态空间E={(x1,x2,…,xn)∣xi∈Si,i=1,2,…,n},给定关于n元组中的一个分量的一个约束集D,要求E中满足D的全部约束条件的所有n元组。
其中Si是分量xi的定义域,且|Si|有限,i=1,2,…,n。
我们称E中满足D的全部约束条件的任一n元组为问题P的一个解。
解问题P的最朴素的方法就是枚举法,即对E中的所有n元组逐一地检测其是否满足D的全部约束,若满足,则为问题P的一个解。
但显然,其计算量是相当大的。
我们发现,对于许多问题,所给定的约束集D具有完备性,即i元组(x1,x2,…,xi)满足D中仅涉及到x1,x2,…,xi的所有约束意味着j(j<=i)元组(x1,x2,…,xj)一定也满足D中仅涉及到x1,x2,…,xj的所有约束,i=1,2,…,n。
换句话说,只要存在0≤j≤n-1,使得(x1,x2,…,xj)违反D中仅涉及到x1,x2,…,xj的约束之一,则以(x1,x2,…,xj)为前缀的任何n元组(x1,x2,…,xj,xj+1,…,xn)一定也违反D中仅涉及到x1,x2,…,xi的一个约束,n≥i≥j。
因此,对于约束集D具有完备性的问题P,一旦检测断定某个j元组(x1,x2,…,xj)违反D中仅涉及x1,x2,…,xj的一个约束,就可以肯定,以(x1,x2,…,xj)为前缀的任何n元组(x1,x2,…,xj,xj+1,…,xn)都不会是问题P的解,因而就不必去搜索它们、检测它们。
回溯法正是针对这类问题,利用这类问题的上述性质而提出来的比枚举法效率更高的算法。
第3章找n个数中r个数的组合问题
3.1问题描述
回溯搜索解找n个数中r个数的组合问题
3.2问题分析
递归算法是找大规模问题和小规模问题的关系,回溯法是对问题的解空间进行深度优先搜索的算法。
必须先确定搜索空间以及约束条件,本题采用回溯搜索算法求解找n个数中r个数的组合问题。
3.3算法设计
不同于递归算法,递归算法是找大规模问题和小规模问题的关系,回溯法是对问题的解空间进行搜索的算法。
(1)问题的解空间为一组r元一维向量,(a1,a2,a3,...,ar),1<=ai<=n,1<=i<=r。
用一维数组a存储正在搜索的向量。
(2)通过实例归纳算法要点。
n=5,r=3,组合结果如下:
543
542
541
532
531
521
432
431
421
321
搜索时依次对数组(一维向量)元素a[1],a[2],a[3]进行尝试:
a[ri]i1-i2;
a[1]尝试范围5--3;
a[2]尝试范围4--2;
a[3]尝试范围3--1;
且有这样的规律:
”后一个元素至少比前一个数小1“;ri+i2均为4=r+1,ri+il均为6=n+1。
(3)主要的数据结构:
归纳为一般情况:
a[1]尝试范围n--r,a[2]尝试范围n-1--r-1,...,a[r]尝试范围n-r--1-1。
由此,搜索过程中的约束条件为ri+a[ri]>=r+1,若ri+a[ri] (4)流程图 图3-1找n个数中r个数流程图 3.4测试结果与分析 测试结果: 图3-2找n个数中r个数问题的解 从图3.1的流程图中可以很清晰地看出问题的数据结构,在图3.2中可以看出问题的解时按照顺序递归地输出的。 从4个数中找出2个数的结果为(4,3)(4,2)(4,1)(3,2)(3,1)(2,1)6种结果。 第4章流水作业车间调度问题 4.1问题描述 n个作业{1,2,....,n}要在由两台机器M1和M2组成的流水线上完成加工。 每个作业加工的顺序都是先在M1上加工,然后在M2上加工。 M1和M2加工作业i所需的时间分别为ai和bi。 流水作业调度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。 作业在机器M1,M2的加工顺序相同。 4.2问题分析 (1)问题的解空间是一棵排列数,简单地解决方法就是在搜索排列数的同时,不断更新最优解,最后找到问题的解。 用数组x(1,2,3,....,n)模拟不同的排列,在不同排列下计算各种排列下的加工耗时情况。 (2)机器M1进行顺序加工,其加工f1时间是固定的,f1[i]=f1[i-1]+a[x[i]]。 机器M2则有可能空闲,或积压的情况,总加工时间f2,当机器M2空间时,f2[i]=f1[i]+b[x[i]];当机器M2有积压情况出现时,f2[i]=f2[i-1]+b[x[i]]。 总加工时间就是f2[n]。 4.3算法设计 (1)一个最优调度应使机器M1没有空闲时间,且M2的空闲时间最少。 在一般情况下,当作业按在机器M1上由小到大排列后,机器M2的空闲时间较少,当然,最少情况一定还与M2上的加工时间有关。 所以,还需要对解空间进行搜索,但排序后可以尽快地找到接近最优的解。 (2)经过排序,就会尽快出现一个接近最优的解,在以后的搜索过程中,当某一排列前几步的加工时间,已经大于当前总加工时间的最小值时,就不进行进一步的搜索计算了,这个操作就称为“限界操作”,它减少了搜索范围,提高了搜索范围。 (3)数据结构设计 1>用二维数组job[100][2]存储作业在M1,M2上的加工时间。 2>由于f1在计算中,只须当前值,所以用变量存储即可;而f2在计算中,还依赖前一个作业的数据,所以有必要用数组存储。 (4)流程图 图4-1流水作业调度主函数流程图 图4-2流水作业调度try()函数流程图 图4-3流水作业调度swap()函数流程图 4.4测试结果与分析 图4-4流水作业车间调度问题的解 由流水作业调度问题分析可知,M1机器是顺序加工,M2机器在加工时有可能出现空闲或积压问题,因此当数据不同时,会根据此两种情况进行分析处理。 第5章结论 在两个实例编程中,总的算法思想都是利用回溯算法求解问题,在n个数中找出r个数实例中,利用递归的算法设计,使算法过程逐步递归地回溯,以便简化问题,进行求解问题。 在流水作业调度问题中,也是利用回溯算法是问题得到最优解。 在通过两个实例编程后,对回溯算法的思想结构以及求解问题的方法有了更深入的理解,对回溯法的解题框架更清楚了。 但在另一方面,也认识到自己的不足之处,比如在调试流水作业调度问题时,对swap()函数没有调试,以为只是一个互换函数,但调试程序时一直出错,最后才明白过来,有关内容的交换,必须利用指针进行交换。 由此,通过两个实例的编程,又使自己收获很多,但还是需要多加学习。 算法 问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯的一个重要特性。 具体来说: 确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。 这个开始结点就成为一个活结点,同时也成为当前的扩展结点。 在当前的扩展结点处,搜索向纵深方向移至一个新结点。 这个新结点就成为一个新的活结点,并成为当前扩展结点。 如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。 此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。 回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。 参考文献 [1]算法设计与分析(第二版)吕国英主编 指导教师评语: 1、文档: a、内容: 不完整□完整□详细□ b、方案设计: 较差□合理□非常合理□ c、实现: 未实现□部分实现□全部实现□ d、文档格式: 不规范□基本规范□规范□ 2、答辩: a、未能完全理解题目,答辩情况较差□ b、部分理解题目,部分问题回答正确□ c、理解题目较清楚,问题回答基本正确□ d、理解题目透彻,问题回答流利□ 文档成绩: ,占总成绩比例: 40% 答辩成绩: ,占总成绩比例: 60% 总成绩: 指导教师签字: 年月日
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 设计 分析 回溯