ImageVerifierCode 换一换
格式:DOCX , 页数:17 ,大小:280.91KB ,
资源ID:6734811      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6734811.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(算法与数据结构程序设计报告B08030111.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

算法与数据结构程序设计报告B08030111.docx

1、算法与数据结构程序设计报告B08030111回溯法应用一、 课题内容和要求在人机对弈、决策问题、人工智能、组合数学等等一系列非数值问题的算法设计中,回溯法是经常采用的一种重要而有效的方法。回溯法是一种选优搜索法。按选择最优解的条件向前搜索,以达到目的。但每当搜索到某一步时,发现其达不到预期的效果,就退回一步重新选择。这种行不通就退回的技术称为回溯法。回溯法的逻辑思路可表示为一棵数,根节点是初始状态,没搜索到一个节点都有若干个可供选择的后续节点,没有任何能够达到目标的暗示,只有走着瞧,不行了就回溯到上一层节点,回复刚刚使用的参数,再走另一条路径,所以回溯法的本质是穷举与试探,找到从根节点到叶子节

2、点的所有正确结果。八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。二、需求分析运用面向对象思想,将八皇后问题的解决放在一个类中来解决。“构造函数模块”用来实现数据的初始化。 “主程序模块”,负责调用其他函数依次在一到八行放置皇后,并按一定规律调整皇后位置,求出八皇后问题的所有解,并输出到文件。“皇后放置模块”,在解决问题过程中,需要将“皇后”依次放置到第一、二、八行。该模块负责尝试在某一行放置一个“皇后”,放置成功返回

3、一个“成功”值,说明当前皇后放置在某一个位置上可能存在“解”。否则失败的话,返回“失败”值,说明当前行无论怎样放置皇后,都得不到解,只有调整上面行的皇后的位置。 “输出模块”,负责将某一种皇后放置的方法写到文件中以供查看。三、概要设计 主类成员变量及函数原型声明:class Queenprivate: int location9; /locationi(i大于,小于等于)表示在(i,location(i))的位置放置了一个“皇后”bool LR16; /LRi(i大于,小于等于)从左上角往右下角数第i条斜线上是否有皇后,true为真 int lr_orgin16; /lr_origin用以记录

4、左上角往右下角数第i条斜线被哪一行的皇后占用,未被占用为0 bool RL16; /RLi(i大于,小于等于)从右上角往左下角数第i条斜线上是否有皇后,true为真 int rl_orgin16; /rl_origin用以记录从右上角往左下角数第i条斜线被哪一行的皇后占用,未被占用为0 bool line9; /linei(i大于,小于等于8)表示在第i列上是否有皇后,true为真 int line_orgin9; /linei(i大于,小于等于8)表示在第i列上被哪一行的皇后占用,未被占用为0 int num; /用以统计解的个数public: Queen(); /构造函数实现数据的初始化b

5、ool mytry(int i); /测试第i行皇后的位置,成功返回true,失败返回false;int SolveProblem(); /八皇后问题的解决void Result(); /输出结果,*8的样式显示,在皇后安放处显示一个Q;成员变量设计:数组location9用来记录一至八行各个皇后所在列的序号(location0不使用)。LR16负责记录从左上角往右下角数,一至十六条斜线是否被占用(即实现皇后间的相互影响)。由于回溯时需要消除已经放置的部分皇后产生的影响(即改变LR16数组的值),所以必须记录某一个值的改变是有哪一行的皇后引起的,否则无法知道哪些影响是该消除的,所以需要设计一个

6、数组lr_origin16,他的元素与LR16一一对应,每当某一条斜线被占用时,先将LR的某一元素的值改变,同时再在lr_origin中相应元素中记录下此改变是由某一行引起的。数组RL16、rl_origin16道理相同,只不过是记录从右上角至左下角第i条斜线的使用情况。此外,某一列是否被占用,被哪一行的皇后占用,也需要记录下来,所以设计bool数组line9,和int型l数组ine_origin9。有了这些,就可以记录某一皇后放置的位置,及产生的影响,同时也可以在需要的时候将相应的影响消除,便于重新放置皇后。成员函数设计:类的构造函数,实现数据的初始化。一个函数负责调用其他函数解决八皇后问题

7、。由于八皇后问题需要不断尝试在某一行放置一个皇后,所以将这一动作也封装到一个函数中,用一个函数实现,第几行放置皇后就将几作为参数传进去。找到一种解法后需要输出结果,将结果的输出放置到一个函数中实现。四、详细设计 1、类的设计具体解释见“概要设计”,不再重复类Queen()的声明:class Queenprivate: int location9; /locationi(i大于,小于等于)表示在(i,location(i))的位置放置了一个“皇后” bool LR16; /LRi(i大于,小于等于)从左上角往右下角数第i条斜线上是否有皇后,true为真 int lr_orgin16; bool

8、RL16; /RLi(i大于,小于等于)从右上角往左下角数第i条斜线上是否有皇后,true为真 int rl_orgin16; bool line9; /linei(i大于,小于等于)表示在第i列上是否有皇后,true为真 int line_orgin9; int num; /统计解法的数量public: Queen(); bool mytry(int i); int SolveProblem(); void Result();2、类Queen的构造函数主要负责将数据初始化,主要是几个数组,将其中的元素全部清零,用于统计方法数的num也置为零:Queen:Queen() /构造函数实现数据的初

9、始化 num=0; int k; for (k=0;k=8;k+) locationk=0; linek=false; line_orgink=0; for (k=0;k0) if (mytry(flag)=true) /如果在第flag行可以找到合适的位置放置“皇后” if(flag=8) num+; /当前是第行皇后找到合适的位置,解法数加一,输出结果 Result(); flag-; /标志位后移一位,即下次继续调整上一行皇后的位置 else flag+; /不是最后一行,则flag加一,继续找下一行的皇后的位置 else flag-; /找不到就把flag减一,即下次调整上一行皇后的位

10、置 return num;4、在第i行放置一个皇后函数。上一步可能是在i-1行成功放置了一个皇后,也有可能是在i+1行放置皇后失败,“回溯”到第i行。所以,如果i+1行放置过皇后,需要将i+1行皇后产生的影响全部消除,然后再尝试在第i放置皇后。如果当前行皇后的位置已经在第八列,则直接返回“失败”。否则,继续尝试。将locationi的值不断加1(当然控制在小于等于八),检查该新的皇后的位置,该列是否被占用,所在的斜线上是否已经放置过皇后。如果有冲突,则继续检查下一列,如果无冲突,则将皇后位置固定,将该列、所在两条斜线置为“被占用”状态,记录下被第i行占用,返回“成功”:bool Queen:m

11、ytry(int i) /测试第i行皇后的位置,成功返回true,失败返回false; int k; if(i+1)=8) locationi+1=0; for(k=0;k=8;k+) if(line_orgink=i|line_orgink=i+1) /i行及以后i+1行皇后放置产生的影响全部消除 line_orgink=0; linek=false; for(k=0;k=15;k+) if(rl_orgink=i|rl_orgink=i+1) /i行及以后i+1行皇后放置在RL斜线上产生的影响全部消除 rl_orgink=0; RLk=false; for(k=0;k=15;k+) if(

12、lr_orgink=i|lr_orgink=i+1) /i行及以后i+1行皇后放置在LR斜线上产生的影响全部消除 lr_orgink=0; LRk=false; if (locationi=8) /如果当前行皇后的位置在最后一列,则放弃往后尝试,直接返回失败 return false; for(+locationi;locationi=8;locationi+) if (linelocationi=0)&(LRi+locationi-1=false)&(RLi-locationi+8=false) /在i行,locationi列可以放置皇后 linelocationi=1; /location

13、i列标记为已占用 line_orginlocationi=i; /locationi列被i行的皇后占用 LRi+locationi-1=true; /从左上往右下角第i+locationi-1条斜线被标记为占用 lr_orgini+locationi-1=i; /从左上往右下角第i+locationi-1条斜线被标记被第i行占用 RLi-locationi+8=true; /从右上往左下角第i-locationi+8条斜线被标记为占用 rl_orgini-locationi+8=i; /从右上往左下角第i-locationi+8条斜线被标记被第i行占用 return true; return

14、false;5、结果输出函数,结果保存在location数组中,为了便于查看,将结果写入到文件“result.txt”中,当然,可以进行适当的格式控制,在8*8的格子中,若未放置皇后显示“_”,反之,显示“Q”:void Queen:Result() /输出结果,8*8的样式显示,在皇后安放处显示一个Q int j,k; ofstream fout(result.txt, ios:app); fout解法num:endl; for (j=1;j=8;j+) for(k=1;klocationj;k+) fout_ ; foutQ ; for(k=locationj+1;k=8;k+) fout

15、_ ; foutendl; foutendlendl;6、main函数,先生成Queen对象,调用其中的SolveProblem方法,最后显示总的解法数目,结束程序:int main() Queen q; cout共有q.SolveProblem()种解法结果保存在“result.txt”中n; return 0;五、测试数据及其结果分析程序运行结果如下:控制台显示解法总数,提示结果保存在“result.txt”中:result.txt保存在当前文件夹下:result.txt中显示皇后的放置方法:六、调试过程中的问题为了解决八皇后问题,第一反应是利用八重循环,一次在八行,八列上放置皇后,从中选

16、择正确解,但是如果对全部位置检查,需要检查88次,耗时太长。接着就考虑使用回溯法,提高效率。回溯法有两个关键问题要考虑:一是如何实现皇后之间的互相影响,即某一列放置皇后后,其他皇后可以“知道”避开这一列;二是回溯以后,调整上一行皇后的位置,那么下一行“皇后”的位置必须“清零”,即从第一列开始重新变化,且消除原来放置时产生的影响。常用方法是利用一个8*8的二维数组,共64个元素,初始值为0,然后放置皇后,每放置一个皇后以后,就将相应的行、列、斜线全部置为1,这样下次放置时,只要看相应位置上的值是否为1,若为1,则表示有冲突,考虑下一个位置。回溯是,将相应的行、列、斜线上的1改为0即可。这样做,比

17、较简单,但是由于回溯的次数很多,如果采用此算法,每次需要修改很多值得大小,效率不高。为了使程序更加简单、快捷。可以考虑利用数个一维数组解决问题。一个一维数组L9表示八列,初始值为false,某一列被占用后,就将相应列的值改为true。同样的道理,再建立两个一维数组,LR16表示从左上角往右下角数的斜线,RL16从右上角往左下角数的斜线,初始值同样置为false,当有皇后放置在该斜线上时,将相应的值改为ture。如果要在第i行,第j列放置一个皇后,只需保证Lj、LRi+j-1、RLi-j+8的值都为false,如果不能保证,则表示有冲突,寻找下一个位置。按照这个思路,我们编写程序,运行起来的不到

18、结果。单步调试发现,问题发生在回溯时的影响消除上。对于影响的消除,我们一开始的设想是这样的:从第i+1行回溯到第i行时,在调整皇后位置之前,先检查locationi+1,将Llocationi+1的值修改成false。但是只有这样是不够的,程序跑不出结果。斜线上的影响也必须消除掉,但是斜线上的几个值都被修改了,无法判断哪个值是第i+1行的皇后放置时修改的。为了解决这一问题,设计一个辅助数组lr_origin16,rl_origin16,用以记录某一条斜线的值被哪一行的皇后修改。初始时值都置为0,当数组LR、RL的元素的值被第i行修改时,将lr_origin、rl_origin的值置为i。回溯到

19、i行时,遍历lr_origin、rl_origin两个数组,如果某一个值等于i+1,就将相应的LR、RL数组元素的值变为false,同时lr_origin、rl_origin的这两个元素值也清零。代码修改如下:for(k=0;k=15;k+) if(rl_orgink=i|rl_orgink=i+1) rl_orgink=0; RLk=false; for(k=0;k0) if (mytry(flag)=true) if(flag=8) num+; Result(); flag-; else flag+; else flag-; 八皇后改进: 八皇后问题做出来以后,将其改进成N皇后问题。N皇后

20、问题与八皇后问题算法思想上类似,区别在于数组规模上,八皇后问题中数组大小是固定的,而在N皇后问题中是不定的,所以需要使用指针,在程序开始时动态的申请内存空间。回溯、判断、修改值时也许要根据N的大小稍作变换。由于N皇后问题结果可能很多(N稍大一点),所以没有将结果写到文件中,而是直接将location数组输出在屏幕上。修改后的几段核心代码如下(全部代码另外提交):初始时输入N并动态申请内存:cout输入皇后数N:n; location=new intn+1; line=new booln+1; line_orgin=new intn+1; LR=new bool2*n; lr_orgin=new

21、 int2*n; RL=new bool2*n; rl_orgin=new int2*n;算法主循环(在8皇后基础上只需将8变成n): while (flag0) if (mytry(flag)=true) if(flag=n) num+; Result(); flag-; else flag+; else flag-; N皇后程序运行效果截图:初始时输入皇后数:输入13后运行结果如下:必须知道的是,单靠回溯法,N皇后问题在N大于15以后,结果就很难出来(需要等很久)。因为潜在的方法数是NN,每当N加1,需要测试的可能性会像几何级数一样迅速增加。除了上面已经实现的n皇后的改进外,还有几点可以改

22、进:1、如果flag+以后,那么是不需要消除影响的,消除影响只是在flag以后,即回溯时需要。2、所需一维数组数量可以进一步减少,LR与lr_origin,RL与rl_origin都只需要保留后者即可,后者为0即表示未被占用,否则表示被占用。七、程序设计总结这次程序设计,做回溯法,一开始没有什么思路,所以事先去网上找了相关的算法思想介绍。详细了解算法思想后,开始独立编写程序。将一段文字描述转化成程序,中间还是有一些困难的。主要问题出在许多细节问题没有搞清楚,就开始编程,结果导致编出来的代码运行不出结果。后来开始单步调试,一步步跟踪,边调试边检查,最后终于发现了程序设计的大漏洞,加以弥补之后,运行,稍加修改,程序终于成功了。由于最后程序编写好之后还剩余一段时间,就利用这段时间,在原有八皇后基础上,改写出了可以解决N皇后问题的程序。但是由于N皇后问题自身的复杂性,以及程序本身算法限制。导致当N大于15以后,结果就很难跑出来,这点以后有待提高。收获:1、对回溯算法有了更加深入的了解。学会了用回溯法解决实际问题。2、学会分析算法的复杂度,并改进程序,提高效率。3、进一步掌握程序单步调试、分析、修改的方法。

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1