回溯法马周游问题实验报告.docx
- 文档编号:27385633
- 上传时间:2023-06-30
- 格式:DOCX
- 页数:15
- 大小:52.06KB
回溯法马周游问题实验报告.docx
《回溯法马周游问题实验报告.docx》由会员分享,可在线阅读,更多相关《回溯法马周游问题实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
回溯法马周游问题实验报告
华南师范大学本科生实验报告
姓名_黎国庄_学号20062101247
院系_计算机学院专业_计算机科学与技术
年级2006级班级_2班_
小组实验任务分工_独立完成
实验时间2008年_6_月3_日
实验名称回溯法的应用
指导老师及职称陈卫东老师
华南师范大学教务处编印
实验课程:
算法分析与设计
实验名称:
回溯法的应用(综设型实验)
第一部分实验内容
1.实验目标
(1)
熟悉使用回溯法求解问题的基本思路。
(2)掌握回溯算法的程序实现方法。
(3)理解回溯算法的特点。
2.实验任务
(1)从所给定的题目中选择一题,使用回溯法求解之。
(2)用文字来描述你的算法思路,包括解空间、限界函数、算法主要步骤等。
(3)在Windows环境下使用C/C++语言编程实现算法。
(4)记录运行结果,包括输入数据,问题解答及运行时间。
(5)分析算法最坏情况下时间复杂度和空间复杂度。
(6)谈谈实验后的感想,包括关于该问题或类似问题的求解算法的建议。
3.实验设备及环境
PC;C/C++等编程语言。
4.实验主要步骤
(1)根据实验目标,明确实验的具体任务;
(2)设计求解问题的回溯算法,并编写程序实现算法;
(3)设计实验数据并运行程序、记录运行的结果;
(4)分析算法时空性能;
(5)实验后的心得体会。
第二部分问题及算法
1.问题描述
给出一个8×8的棋盘,一个放在棋盘某个位置上的马(规定马的走法为走“日”)是否可以恰好访问每个方格一次,并回到起始位置上?
2.回溯法的一般思路
对于马所在其中一格时,它可以走的位置有以下8种情况:
⑧①
⑦②
马
⑥③
⑤④
所以对于每一个马所在的格子里,马可以走对应的8个方向。
用满8叉树,每一个子树对应马可跳的方向
当要走下一子树(跳下一格)时,该子树可走(还没有走过并且在棋盘里边),即沿该方向走下去,当不可以走,即回溯到上一步,选择另一方向往下走;当该子树的8个子棋都遍历完了(即8个方向都走过了),则回溯到它父亲那里。
重复一直做下去,到棋盘每个格子都走过一遍,而且回到出发点或者找不到路径即结束。
3.求解问题的回溯算法描述
算法如下:
输入:
V(x,y)马开始的起点
输出:
马从第一步到最后一步(64)的先后次序数字
1.v←()
2.flag←false
3.k←1
4.whilek≥1
5.whileX
没有被穷举
6.x
←X
中的下一个元素;将x
加入v
7.ifv为最终解thensetflag←true,且从两个while循环退出
8.elseifv是部分解thenk←k+1{前进}
9.endwhile
10.重置X
,使得下一个元素排在第一位
11.K←k-1{回溯}
12.endwhile
13.ifflagthenoutputv
14.elseoutput“nosolution”
4.算法实现的关键技巧
voidexit(pointp)
参数:
point
功能:
计算出下一步可能位置,按其各个位置下一个位置的和压栈到s[]中
算法描述:
接受参数传来的值,按次序加上
inthorizontal[]={2,1,-1,-2,-2,-1,1,2};
intvertical[]={-1,-2,-2,-1,1,2,2,1};
再根据legal函数来判断是否合法(x(0~7),y(0~7))是,则保存在pointap[]中,再按各自下一步的数目从大到小排序。
最后,将ap[]中的点压栈。
intnumber(pointp)
参数:
point
功能:
找出当前位置下一步的各种可能位置,计算可能之和
算法描述:
接受参数传来的值,按次序加上
inthorizontal[]={2,1,-1,-2,-2,-1,1,2};
intvertical[]={-1,-2,-2,-1,1,2,2,1};
再根据legal函数来判断是否合法(x(0~7),y(0~7))是,则加1并将值返回
voidnext(pointp)
参数:
point
功能:
/找出各个位置并将其步数记录
算法描述:
将其步数记录在board[][]的相应位置,并将这点压栈到s1,判断步数是否小于64,再根据这四个条件选择执行其中的一个,再递归调用next.
boollegal(pointp)
参数:
point
功能:
判断是否可行,合法(是否在棋盘上,是否走过)
算法描述:
用这样的语句if((p.x>=0)&&(p.x
returntrue;
else
returnfalse;
第三部分实验结果与分析
1.实验数据及结果
测试数据和运行输出及结果
2.实验分析及结论
实验框架
具体分析见回溯法的一般思路
结论:
马可以从任何一格出发恰好访问每个方格一次,并回到起始位置上。
第四部分心得与展望
1.自我评价及心得体会
评价:
整个算法的实现挺完整的
体会:
算法中的每个函数的功能尽量单一,调用函数时要注意是否修改了其他参数的值。
一定要静下心去做。
调试也很重要,从中能知道错在哪里。
2.展望
据知用启发式搜索会更快一点,但现在我还是没有学会用这种方法解决这个问题。
第五部分附录
1.程序主要界面
2.源程序
//SqStack.h
#pragmaonce
#defineOK1
#defineERROR0
#defineOVERFLOW-2
#defineSTACK_INIT_SIZE8
#defineSTACKINCREMENT57
typedefstruct
{
intx,y;
}point;
typedefpointSElemType;
typedefintStatus;
typedefstruct
{
SElemType*base;
SElemType*top;
intstacksize;
}SqStack;
StatusInitStack(SqStack&s);
StatusPush(SqStack&s,SElemTypee);
StatusPop(SqStack&s,SElemType&e);
//SqStack..cpp
#include"SqStack.h"
#include
#include
StatusInitStack(SqStack&s)
{
s.base=(SElemType*)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!
s.base)returnOVERFLOW;
s.top=s.base;
s.stacksize=STACK_INIT_SIZE;
returnOK;
}
StatusPush(SqStack&s,SElemTypee)
{
if(s.top-s.base>=s.stacksize)
{
s.base=(SElemType*)realloc(s.base,(STACK_INIT_SIZE+STACKINCREMENT)*sizeof(SElemType));
if(!
s.base)
{
returnOVERFLOW;
}
s.top=s.base+s.stacksize;
s.stacksize+=STACKINCREMENT;
}
*s.top++=e;
returnOK;
}
StatusPop(SqStack&s,SElemType&e)
{
if(s.top==s.base)
returnERROR;
e=*--s.top;
returnOK;
}
//horse.cpp
#include
#include
#include"SqStack.h"
inthorizontal[]={2,1,-1,-2,-2,-1,1,2};
intvertical[]={-1,-2,-2,-1,1,2,2,1};
intboard[8][8]={0};
intstep=1;
SqStacks[65];
SqStacks1;
#definen8
voidexit(pointp);//计算出下一步可能位置,按其各个位置下一个位置的和压栈到s[]中
intnumber(pointp);//找出当前位置下一步的各种可能位置,计算可能之和
voidnext(pointp);//找出各个位置并将其步数记录
boollegal(pointp);//判断是否可行
voidmain()
{
pointp;
printf("\n");
printf("***************欢迎使用回溯法解决马周游问题****************\n\n");
printf("***************下面请输入马的初始位置坐标x(0-%d),y(0-%d):
\n",n-1,n-1);
printf("\n");
scanf("%d%d",&p.x,&p.y);
printf("\n");
printf("周游路线如下:
\n");
printf("\n");
while(!
((p.x>=0)&&(p.x
{
printf("输入不合法,请重新输入!
\n");
printf("\n");
printf("请重新输入马的初始位置x(0-%d!
),y(0-%d!
):
\n",n-1,n-1);
printf("\n");
scanf("%d%d",&p.x,&p.y);
printf("\n");
printf("周游路线如下:
\n");
printf("\n");
}
InitStack(s1);//初始化栈
next(p);
for(inti=0;i { for(intj=0;j { printf("%5d",board[i][j]); } printf("\n"); } printf("此次周游完毕! \n"); main(); } intnumber(pointp)//找出当前位置下一步的各种可能位置,计算可能之和 { pointp1; intj=0; for(inti=0;i<8;i++) { p1.x=p.x+horizontal[i]; p1.y=p.y+vertical[i]; if(legal(p1)) { j++; } } return(j); } voidnext(pointp)//找出各个位置并将其步数记录 { pointp1,p2; InitStack(s[step]); board[p.x][p.y]=step; Push(s1,p); if(step { exit(p); Pop(s[step],p2); if((s[step].base==s[step].top&&number(p2)==0)&&step! =n*n-1) { Pop(s1,p1); board[p1.x][p1.y]=0; --step; while(s[step].base==s[step].top) { Pop(s1,p1); board[p1.x][p1.y]=0; step--; } Pop(s[step],p2); step++; next(p2); }//退栈,悔棋 elseif(number(p2)==0&&s[step].base! =s[step].top) { Pop(s[step],p2); step++; next(p2); } elseif(number(p2)! =0&&s[step].base==s[step].top) { step++; next(p2); } else { step++; next(p2); } } } voidexit(pointp)//计算出下一步可能位置,按其各个位置下一个位置的和压栈到s[]中 { pointtemp; pointp1; intj=0; pointap[8]={0}; for(inti=0;i<8;i++) { p1.x=p.x+horizontal[i]; p1.y=p.y+vertical[i]; if(legal(p1)) { ap[j]=p1; j++; } }//将下一步的可能位置储存在ap[]中 for(intcount=0;count { for(intk=0;k { if(number(ap[k]) { temp=ap[k+1]; ap[k+1]=ap[k]; ap[k]=temp; } } } for(intt=0;t { Push(s[step],ap[t]); }//将可能位置压栈到s[step] } boollegal(pointp)//判断是否可行 { if((p.x>=0)&&(p.x returntrue; else returnfalse; } 参考文献 [1]算法设计技巧与分析[沙特]M.H.Alsuwaiyel著(电子工业出版社) [2]数据结构与算法黄定黄煜廉刘贤兴编(广东科技出版社)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 回溯 周游 问题 实验 报告