A星八数码求解教学内容.docx
- 文档编号:24012922
- 上传时间:2023-05-23
- 格式:DOCX
- 页数:14
- 大小:119.42KB
A星八数码求解教学内容.docx
《A星八数码求解教学内容.docx》由会员分享,可在线阅读,更多相关《A星八数码求解教学内容.docx(14页珍藏版)》请在冰豆网上搜索。
A星八数码求解教学内容
A星八数码求解
实验二A*算法实验I
软工1303201326811825朱镇洋
一、实验目的:
熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解N数码难题,理解求解流程和搜索顺序。
二、实验原理:
A*算法是一种启发式图搜索算法,其特点在于对估价函数的定义上。
对于一般的启发式图搜索,总是选择估价函数f值最小的节点作为扩展节点。
因此,f是根据需要找到一条最小代价路径的观点来估算节点的,所以,可考虑每个节点n的估价函数值为两个分量:
从起始节点到节点n的实际代价以及从节点n到达目标节点的估价代价。
三、实验内容:
1 问题描述。
八数码问题:
在一个3×3的方阵中放入八个数码1、2、3、4、5、6、7、8,其中一个单元格是空的。
将任意摆放的数码盘(初始状态)逐步摆成某个指定的数码盘的排列(目标状态):
2 设计两种不同的估价函数。
w(n);w表示不在目标位置的节点数
h(n)=d(n)+;d(n)表示深度
p(n);p表示所有点到其目标节点的步数总和
算法流程图:
3 在求解8数码问题的A*算法程序中,设置相同的初始状态和目标状态,针对不同的估价函数,求得问题的解
令初始状态都为:
023415687目标状态为:
123405678
通过程序运行结果我们可以发现,上述两种估价函数中明显第二种在算法效率上更具优势,第一种估价函数要通过18步才能到达目标状态,通过中间变量记录扩展节点和生成节点有1062个:
而第二种估价函数只要16步即可到达目标状态,也意味着扩展节点和生成节点只有654个,比第一种少了很多:
原因分析:
通过实验结果也说明了估计函数对启发式搜索算法的重要影响,因为第二种估价函数p(n)是节点与目标节点相比所需移动次数的总和,与第一种估价函数w(n)(只考虑错误位数)相比,p(n)不仅考虑了错位信息,还考虑了错位的距离,比w(n)更完美,所以它的执行效率更高。
4启发式算法特点。
启发式搜索算法的基本思想是:
定义一个估价函数f,对当前的搜索状态进行评估,找出一个最有希望的节点来扩展。
先定义下面几个函数的含义:
f*(n)=g*(n)+h*(n)式中g*(n)表示从初始节点s到当前节点n的最短路径的耗散值;h*(n)表示从当前节点n到目标节点g的最短路径的耗散值,f*(n)表示从初始节点s经过n到目标节点g的最短路径的耗散值。
估价函数的形式可定义如下式所示:
f(n)=g(n)+h(n)其中n是被评价的当前节点。
f(n)、g(n)和h(n)分别表示是对f*(n)、g*(n)和h*(n)3个函数值的估计值。
利用估价函数f(n)=g(n)+h(n)来排列open表节点顺序的图搜索算法称为算法A。
在A算法中,如果对所有的x,
h(x)<=h*(x)成立,则称好h(x)为h*(x)的下界,它表示某种偏于保守的估计。
采用h*(x)的下界h(x)为启发函数的A算法,称为A*算法。
5扩展。
稍微改进了给定的算法,给定的算法中时在求解之后才确定是否有解,而其实判断一个八数码是否有解在输入时即可判断出该是否有解。
只要将每位上(除了空格)的特定值(此位之前比该数小的个数)相加,如果得数为偶数,那么可以确定最后有解,否则无解。
所以可以在每次输入时判断是否有解,而不必在计算完再确定是否有解,这样在算法的时间复杂度上有很大的提升,该段代码如下:
if(!
pq.empty())
{
intflag=0;
cur=pq.top();
for(inti=0;i<9;i++)
{
for(intj=0;j
{
if(cur.s[i]=='0'||cur.s[j]=='0')
continue;
else{
if(cur.s[j] flag++; } } } if(flag%2! =0) return-1;//搜索失败 } 6源程序(采用上述中更高效的第二种估价函数)。 //************************************ //*八数码问题 //************************************ #include #include #include #include #include usingnamespacestd; structP{ intd;//深度g(n) intw;//不在位数h(n) intid;//记录该节点的id,用于输出时找到该节点 strings;//状态 friendbooloperator<(constP&a,constP&b){//按f(n)=g(n)+h(n)大小排序 returna.d+a.w>b.d+b.w;//最大堆 } }p; constintN=3;//棋盘大小 conststringt="123405678";//目标状态 stringstack[1000000];//记录搜索中的节点 stringrecord[1000000];//从起点开始记录解路径 intfather[10000000];//记录该节点的父节点 inttop=0;//stack的指针 priority_queue pq;//open表 map 1访问过,0没有 intcalw(strings)//计算该状态的不在位数h(n) { intre=0; for(inti=0;i<9;i++) { re+=abs(s[i]-t[i]); } returnre; } intsolve(int&num)//搜索过程 { Pcur; if(! pq.empty()) { intflag=0; cur=pq.top(); for(inti=0;i<9;i++) { for(intj=0;j { if(cur.s[i]=='0'||cur.s[j]=='0') continue; else{ if(cur.s[j] flag++; } } } if(flag%2! =0) return-1;//搜索失败 } while(! pq.empty()){ num++; cur=pq.top();//open表 pq.pop(); if(cur.s==t)returncur.id;//达到目标状态,返回当前节点的id intx,y; intops=0; while(cur.s[ops]! ='0')ops++; x=ops/3,y=ops%3;//空格所在位置 intr=cur.id; if(x>0){//空格向上移 p.s=cur.s; swap(p.s[ops],p.s[ops-3]); if(! mp[p.s]){ p.d=cur.d+1,p.w=calw(p.s),p.id=top+1; pq.push(p); stack[++top]=p.s; father[top]=r; mp[p.s]=1; } } if(x<2){//空格向下移 p.s=cur.s; swap(p.s[ops],p.s[ops+3]); if(! mp[p.s]){ p.d=cur.d+1,p.w=calw(p.s),p.id=top+1; pq.push(p); stack[++top]=p.s; father[top]=r; mp[p.s]=1; } } if(y>0){//空格向左移 p.s=cur.s; swap(p.s[ops],p.s[ops-1]); if(! mp[p.s]){ p.d=cur.d+1,p.w=calw(p.s),p.id=top+1; pq.push(p); stack[++top]=p.s; father[top]=r; mp[p.s]=1; } } if(y<2){//空格向右移 p.s=cur.s; swap(p.s[ops],p.s[ops+1]); if(! mp[p.s]){ p.d=cur.d+1,p.w=calw(p.s),p.id=top+1; pq.push(p); stack[++top]=p.s; father[top]=r; mp[p.s]=1; } } } } voidprint(intx)////从record表中输出当前搜索的节点 { intk=0; for(inti=0;i for(intj=0;j if(record[x][k]=='0') printf(""); elseprintf("%c",record[x][k]); k++; } printf("\n"); } printf("\n"); } intmain() { //freopen("a.txt","r",stdin); inttt;//测试的组数 cin>>tt; for(intk=1;k<=tt;k++){ cout<<"Case"< \n"; inti,j; chara; p.s=""; for(i=0;i for(j=0;j cin>>a;//输入0? 8数码 p.s+=a; } } p.d=0,p.w=calw(p.s),p.id=0; father[0]=-1; mp[p.s]=1; stack[0]=p.s; pq.push(p);//往open表中加入初始状态节点 intnum=0; intid=solve(num);//调用搜索过程 if(id==-1){ cout<<"无解! \n"; }else{ intc=-1; while(id>=0){//把stack中存的节点按次序放入到record中 record[++c]=stack[id]; id=father[id]; } cout<<"原图: "< print(c);//输出初始节点 cout<<"移动过程: \n\n"; for(i=c-1;i>=0;i--){ cout<<"Step"< \n";//输出当前搜索步骤 print(i);//输出当前搜索的节点 } cout<<"移动结束! \n"; } mp.clear(); while(! pq.empty())pq.pop(); top=0; cout< "< cout< } system("pause\n"); return0; } 第一种估价函数源代码: intcalw(strings)//计算该状态的不在位数h(n) { intre=0; for(inti=0;i<9;i++)if(s[i]! =t[i])re++; returnre; } 三、实验小结: 通过此次实验,我对启发式搜索有了更深的了解,在处理该实验时,给定的两种估价函数差别不大都可以接受,但如果处理一些复杂的问题,第二种估价函数显然更为优秀,可以避免不必要的扩展。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数码 求解 教学内容