回溯算法的应用.docx
- 文档编号:27271232
- 上传时间:2023-06-28
- 格式:DOCX
- 页数:16
- 大小:109.54KB
回溯算法的应用.docx
《回溯算法的应用.docx》由会员分享,可在线阅读,更多相关《回溯算法的应用.docx(16页珍藏版)》请在冰豆网上搜索。
回溯算法的应用
回溯算法的应用
课程名称:
算法设计与分析
院系:
************************
学生姓名:
******
学号:
************
专业班级:
*****************************
指导教师:
******
2013年12月27日
回溯法的应用
摘要:
回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。
但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
回溯法,其意义是在递归直到可解的最小问题后,逐步返回原问题的过程。
而这里所说的回溯算法实际是一个类似枚举的搜索尝试方法,它的主题思想是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
回溯算法是尝试搜索算法中最为基本的一种算法,其采用了一种“走不通就掉头”的思想,作为其控制结构。
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。
当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
全排列和求最优解问题是比较经典的问题,我们可以采用多种算法去求解此问题,比如动态规划法、分支限界法、回溯法。
在这里我们采用回溯法来解决这个问题。
关键词:
回溯法全排列最优值枚举
第1章绪论
1.1回溯法的背景知识
回溯算法是尝试搜索算法中最为基本的一种算法,其采用了一种“走不通就掉头”的思想,作为其控制结构。
在递归算法中,其存在的意义是在递归知道可解的最小问题后,逐步返回原问题的过程。
实际上是一个类似于枚举的搜索尝试方法,他的主题思想是在搜索尝试的过程中寻找问题的解,当发现不满足条件时就回溯返回,尝试别的路径。
简单的说就是:
从问题的某一种初始状态出发,依次搜寻每一种可能到达的情况,当走到这条路的“尽头”时,回过头到上一个情况,看这个情况是否还有没有走过的路,依次进行下去,直到遍历完所有的情况。
回溯法实际上是一种深度优先搜索的方式。
对于回溯法解决的问题,通常将其解空间组织成图或者树的形式。
对于用回溯法求解的问题,首先要将问题进行适当的转化,得出状态空间树。
这棵树的每条完整路径都代表了一种解的可能。
通过深度优先搜索这棵树,枚举每种可能的解的情况;从而得出结果。
但是,回溯法中通过构造约束函数,可以大大提升程序效率,因为在深度优先搜索的过程中,不断的将每个解与约束函数进行对照从而删除一些不可能的解,这样就不必继续把解的剩余部分列出从而节省部分时间。
1.2回溯法的前景意义
在做题时,有时会遇到这样一类题目,它的问题可以分解,但是又不能得出明确的动态规划或是递归解法,此时可以考虑用回溯法解决此类问题。
回溯法的优点在于其程序结构明确,可读性强,易于理解,而且通过对问题的分析可以大大提高运行效率。
通过运用回溯法,可以解决很多问题,譬如我们所熟知的“八皇后问题”、“0/1背包问题”,这只是在教学阶段中的运用,在实际运用中回溯法也能起到很大的作用。
回溯法适用于解决难以归纳一般规律解法的问题,其适用范围广,灵活性大,在解一些列举方法的问题时尤其可用。
但是,其缺点也是明显的,即时间复杂度较大;因此在采用时我们应该因情况的不同而做出不同的选择。
第2章回溯法的理论知识
2.1问题的解空间树
对于全排列问题。
对n位数进行全排列,知道了这个数的位数就知道有多少种排列方法,在n位数中选定一个数为首位就可以进行下面的排列。
当n=4时,我们要从一个数开始排列,再进行其他两位数。
假设排列从1开始出发,则可能的路径如下图2.1。
图2.1选择的路径
活结点:
不是叶结点,满足约束条件,使目标函数有所改善,儿子结点有尚未访问的(可继续搜索下去)。
否则为死结点。
E-结点:
扩展结点,当前正在搜索的活结点。
死结点:
即如果取了这个结点,将不会有可行解。
2.2回溯法的一般性描述
回溯法的一般描述
可用回溯法求解的问题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的全排列
3.1问题描述
输出自然数1到n所有不重复的全排列。
3.2问题分析
在n的全排列是一组n元一维向量,(x1,x2,x3,…,xn),搜索空间是:
1<=xi<=ni=1,2,3…,n
约束条件很简单,xi互不相同。
3.3算法设计
1、算法介绍
本例题采用“数组记录状态信息”的方法检查在搜索过程中是否满足约束条件。
一般的方法是用cheak( )函数进行判断,cheak( )函数中当前元素与前面的元素进行逐个比较。
而在这个算法中用的是try()函数,是搜索的过程更加快。
voidTRY(intk)//找第k个数
{intj;
for(j=1;j<=n;j++)
{if(d[j]==0)//判断第k个数是否可用
{a[k]=j;
d[j]=1;}
else
continue;//第k个数不可用
if(k TRY(k+1);//找第k+1个数 else{ p++; output();}//输出元素 d[a[k]]=0;//将数组中的数设为未使用 } } 具体方式为: 设置n个元素的一维数组d,在该算法中的一维数组d用于记录数组中的元素的状态(是否被搜索过),其中的n个元素用来记录数据1~n的使用情况,已使用置1,未使用置0。 直到所有元素的已使用,输出结果;然后循环进行,直到输出所有排列。 在该算法中最重要的一个函数就是d[a[k]]=0,这是回溯的核心,用以上回溯法搜索算法完成算法的全排列问题的复杂度为O(n^n),不是最佳算法。 如果在算法中运用try()函数自身之间的交换,for循环语句for(j=t;j<=n;j=j+1),而且for循环体中的第二个swap()调用,是用来恢复原顺序的,在每次回溯时,都要恢复本次操作前的原始操作。 这个全排列算法的复杂度为O(n! ),其结果可以为搜索排列树所用。 2、流程图 3.4测试结果与分析 (1)测试结果: 图3.1全排列问题的解 图3.2全排列问题的解 (2)对测试结果的分析: 从图3.1、3.2中可以看出全排列的排列方法,当n=2时有两种排列,当n=3时有六种排列,所以对于n的全排列有n! 种排列方法。 第4章最优化问题 4.1问题描述 一个有趣的高精度数据: 构造一个尽可能大的数,使其从高到低满足前一位能被1整除,前2位能被2整除,……,前n位能被n整除。 数学模型: 记高精度数据为a1,a2,…,an,题目很明确有两个要求: (1)a1能被1整除且(a1*10+a2)能被2整除且……(a1*10^n-1+a2*10^n-2+…+an)能被能整除; (2)求最大的这样的数。 a1能被1整除且(a1*10+a2)能被2整除且……(a1*10^n-1+a2*10^n-2+…+an)能被能整除; 4.2问题分析 此数只能用从高位到低位逐位尝试,失败回溯的算法策略求解,生成的高精度数据用数组从高位到低位存储,1号元素开始存储最高位。 此数的大小无法估计不妨为数组开辟100个空间。 4.3算法设计 1、算法介绍 算法中数组A位当前求解的高精度数据的暂存处,数组B为当前最大的满足条件的数。 算法的首位A[1](最高位)从1开始枚举。 以后各位从0开始枚举。 所以求解出的满足条件的数据之间只须比较位数就能确定大小。 n为当前满足条件的最大数据的位数,i为当前满足条件数据的位数,当i>=n就认为找到了更大的解。 当i>n不必解释,位数多数据一定大;i=n时,由于尝试是由小到大进行的,虽然位数相等,但后来满足条件的数据一定比前面的大。 (1)从A[1]=1开始,每增加一位A[i](初值为0)先计算r=(A[1]*10^i-1+A[2]*10^i-2+…+A[i]),再测试r=rmodi是否。 (2)r=0表示增加第i位后,满足条件,与原有满足条件的数(存在数组B中)比较,若前者大,则更新后者(数组B),继续增加下一位。 (3)r! 0表示增加i位不满足整除条件,接下来算法中并不是继续尝试A[i]=A[i]+1,而是继续尝试A[i]=A[i]+i-r,因为若A[i]=A[i]+i-r<=9时,(A[1]*10^i-1+A[2]*10^i-2+…+A[i]-r+i)modi肯定为0.这样可以减少尝试次数。 如: 17除5余2,17-2+5肯定能被5整除。 (4)同理,当A[i]-r+i>9时,要进位也不能满足条件。 这时,只能将此恢复初值0且回退到前一位(i=i-1)尝试A[i]=A[i]+1,以此类推……。 这正是算法中最后一个while循环所做的工作。 (5)当回溯到i=1时,A[1]加1开始尝试首位为2的情况,最后直到将A[1]=9的情况尝试完毕,算法结束。 主要的函数及功能 while(A[1]<=9) {if(i>=n)//判断i的值 {n=i;//转存到数组B中 for(k=1;k<=n;k=k+1) B[k]=A[k];} i=i+1; r=0; for(j=1;j<=i;j=j+1)//第i位是否满足条件 {r=r*10+A[j]; r=r%i;} if(r! =0) {A[i]=A[i]+i-r;//第i位可能的解 while(A[i]>9&&i>1)//搜索完第i位的解,回溯到前一位 {A[i]=0; i=i-1; A[i]=A[i]+i; } 2、流程图 4.4测试结果与分析 (1)测试结果: 图4.1最优值 (2)对测试结果的分析: 对输出的数据进行检验,例如3能被1整除,36能被2整除,360能被3整除,3608能被4整除……检查完输出结果的所有数位发现满足题意,说明结果是正确的,该算法使用与此类问题的求解。 第5章结论 通过本次课程设计,我对回溯法有了更为深入的理解,学会了用回溯法解决相关问题的思路。 在本次课程设计的过程中,小组遇到了一些问题,比如: 开始时,对于深度优先搜索知识的欠缺,在查找时产生错误;回溯函数放错了地方等。 对于其中出现的问题经过我们的讨论以及查阅相关的资料都得到了解决,并在讨论的过程中对知识的理解更为深刻。 回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。 回溯算法的基本思想是: 从一条路往前走,能进则进,不能进则退回来,换一条路再试。 用回溯算法解决问题的一般步骤为: 1、定义一个解空间,它包含问题的解。 2、利用适于搜索的方法组织解空间。 3、利用深度优先法搜索解空间。 4、利用限界函数避免移动到不可能产生解的子空间。 问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。 具体来说: 确定了解空间的组织结构后,回溯法就从开始结点(根结点)出发,以深度优先的方式搜索整个解空间。 这个开始结点就成为一个活结点,同时也成为当前的扩展结点。 在当前的扩展结点处,搜索向纵深方向移至一个新结点。 这个新结点就成为一个新的活结点,并成为当前扩展结点。 如果在当前的扩展结点处不能再向纵深方向移动,则当前扩展结点就成为死结点。 此时,应往回移动(回溯)至最近的一个活结点处,并使这个活结点成为当前的扩展结点。 回溯法即以这种工作方式递归地在解空间中搜索,直至找到所要求的解或解空间中已没有活结点时为止。 参考文献 [1]算法设计与分析(第二版)吕国英主编 附件 全排列问题源程序: #include intp=0,n,a[100],d[100]; voidoutput() { intj; printf("%d\n",p);//p为第几组排列 for(j=1;j<=n;j++) printf("%d",a[j]);//输出排列 printf("\n"); } voidTRY(intk)//找第k个数 { intj; for(j=1;j<=n;j++) { if(d[j]==0)//判断第k个数是否可用 { a[k]=j; d[j]=1; } else continue;//第k个数不可用 if(k TRY(k+1);//找第k+1个数 else { p++; output();//输出元素 } d[a[k]]=0;//将数组中的数设为未使用 } } intmain() { intj; printf("Inputn=");//输入n scanf("%d",&n); for(j=1;j<=n;j++)//函数完成初始化 d[j]=0; TRY (1); return; } 最优化问题源程序: #include intmain(){ intA[101],B[101]; inti,j,k,n,r; A[1]=1; for(i=2;i<=100;i=i+1)//置初值: 首位为1,其余为0 A[i]=0; n=1; i=1; while(A[1]<=9) { if(i>=n)//判断i的值 { n=i;//转存到数组B中 for(k=1;k<=n;k=k+1) B[k]=A[k]; } i=i+1; r=0; for(j=1;j<=i;j=j+1)//第i位是否满足条件 { r=r*10+A[j]; r=r%i; } if(r! =0) { A[i]=A[i]+i-r;//第i位可能的解 while(A[i]>9&&i>1)//搜索完第i位的解,回溯到前一位 {A[i]=0; i=i-1; A[i]=A[i]+i; } } } printf("maxis: "); for(i>0;i<=n;i++){ printf("%d",B[i]); } } 指导教师评语: 1、文档: a、内容: 不完整□完整□详细□ b、方案设计: 较差□合理□非常合理□ c、实现: 未实现□部分实现□全部实现□ d、文档格式: 不规范□基本规范□规范□ 2、答辩: a、未能完全理解题目,答辩情况较差□ b、部分理解题目,部分问题回答正确□ c、理解题目较清楚,问题回答基本正确□ d、理解题目透彻,问题回答流利□ 文档成绩: ,占总成绩比例: 40% 答辩成绩: ,占总成绩比例: 60% 总成绩: 指导教师签字: 年月日
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 回溯 算法 应用