八数码问题C语言A星算法详细实验报告含代码.docx
《八数码问题C语言A星算法详细实验报告含代码.docx》由会员分享,可在线阅读,更多相关《八数码问题C语言A星算法详细实验报告含代码.docx(14页珍藏版)》请在冰豆网上搜索。
八数码问题C语言A星算法详细实验报告含代码
一、实验内容和要求
八数码问题:
在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
例如:
2
8
3
1
2
3
1
6
4
8
4
7
0
5
7
6
5
(a)初始状态(b)目标状态
图1八数码问题示意图
请任选一种盲目搜索算法(广度优先搜索或深度优先搜索)或任选一种启发式搜索方法(全局择优搜索,加权状态图搜索,A算法或A*算法)编程求解八数码问题(初始状态任选)。
选择一个初始状态,画出搜索树,填写相应的OPEN表和CLOSED表,给出解路径,对实验结果进行分析总结,得出结论。
二、实验目的
1.熟悉人工智能系统中的问题求解过程;
2.熟悉状态空间的盲目搜索和启发式搜索算法的应用;
3.熟悉对八数码问题的建模、求解及编程语言的应用。
三、实验算法
A*算法是一种常用的启发式搜索算法。
在A*算法中,一个结点位置的好坏用估价函数来对它进行评估。
A*算法的估价函数可表示为:
f'(n)=g'(n)+h'(n)
这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值(也称为最小耗费或最小代价),h'(n)是n到目标的最短路经的启发值。
由于这个f'(n)其实是无法预先知道的,所以实际上使用的是下面的估价函数:
f(n)=g(n)+h(n)
其中g(n)是从初始结点到节点n的实际代价,h(n)是从结点n到目标结点的最佳路径的估计代价。
在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。
用f(n)作为f'(n)的近似,也就是用g(n)代替g'(n),h(n)代替h'(n)。
这样必须满足两个条件:
(1)g(n)>=g'(n)(大多数情况下都是满足的,可以不用考虑),且f必须保持单调递增。
(2)h必须小于等于实际的从当前节点到达目标节点的最小耗费h(n)<=h'(n)。
第二点特别的重要。
可以证明应用这样的估价函数是可以找到最短路径的。
3.A*算法的步骤
A*算法基本上与广度优先算法相同,但是在扩展出一个结点后,要计算它的估价函数,并根据估价函数对待扩展的结点排序,从而保证每次扩展的结点都是估价函数最小的结点。
A*算法的步骤如下:
1)建立一个队列,计算初始结点的估价函数f,并将初始结点入队,设置队列头和尾指针。
2)取出队列头(队列头指针所指)的结点,如果该结点是目标结点,则输出路径,程序结束。
否则对结点进行扩展。
3)检查扩展出的新结点是否与队列中的结点重复,若与不能再扩展的结点重复(位于队列头指针之前),则将它抛弃;若新结点与待扩展的结点重复(位于队列头指针之后),则比较两个结点的估价函数中g的大小,保留较小g值的结点。
跳至第五步。
4)如果扩展出的新结点与队列中的结点不重复,则按照它的估价函数f大小将它插入队列中的头结点后待扩展结点的适当位置,使它们按从小到大的顺序排列,最后更新队列尾指针。
5)如果队列头的结点还可以扩展,直接返回第二步。
否则将队列头指针指向下一结点,再返回第二步。
四、程序框图
五、实验结果及分析
输入初始状态:
283目标状态:
123
164804
705765
运行结果屏幕打印
OPEN表与CLOSE表:
OPEN
CLOSE
1234
0
23456
01
23467
015
234689
0157
2348910
01576
2348111213
015769
234812131415
01576911
348121314151617
015769112
481213141516171819
0157691123
481213141516171920
015769112318
8121314151617192122
0157691123184
12131415161719212223
01576911231848
1213141516171921222425
0157691123184823
1213141516171921222426
015769112318482324
发现26为目标节点
搜索树:
六、结论
对于八数码问题,BFS算法最慢,A*算法较快。
八数码问题的一个状态实际上是0~9的一个排列,对于任意给定的初始状态和目标,不一定有解,也就是说从初始状态不一定能到达目标状态。
因为排列有奇排列和偶排列两类,从奇排列不能转化成偶排列。
如果一个数字0~8的随机排列871526340,用F(X)表示数字X前面比它小的数的个数,全部数字的F(X)之和为Y=∑(F(X)),如果Y为奇数则称原数字的排列是奇排列,如果Y为偶数则称原数字的排列是偶排列。
因此,可以在运行程序前检查初始状态和目标状态的排序的奇偶行是否相同,相同则问题可解,应当能搜索到路径。
否则无解。
七、源程序及注释
#include
#include
#include
usingnamespacestd;
constintROW=3;
constintCOL=3;
constintMAXDISTANCE=10000;
constintMAXNUM=10000;
intabs(inta)
{
if(a>0)returna;
elsereturn-a;
}
typedefstruct_Node{
intdigit[ROW][COL];
intdist;//距离
intdep;//深度
intindex;//索引值
}Node;
Nodesrc,dest;
vectornode_v;//储存节点
boolisEmptyOfOPEN(){//判断Open表是否空
for(inti=0;iif(node_v[i].dist!
=MAXNUM)
returnfalse;
}
returntrue;
}
boolisEqual(intindex,intdigit[][COL]){//判断节点是否与索引值指向的节点相同
for(inti=0;ifor(intj=0;j
if(node_v[index].digit[i][j]!
=digit[i][j])
returnfalse;
}
returntrue;
}
ostream&operator<<(ostream&os,Node&node){
for(inti=0;ifor(intj=0;j
os<os<}
returnos;
}
voidPrintSteps(intindex,vector&rstep_v){//输出步骤
rstep_v.push_back(node_v[index]);
index=node_v[index].index;
while(index!
=0){
rstep_v.push_back(node_v[index]);
index=node_v[index].index;
}
for(inti=rstep_v.size()-1;i>=0;i--)
cout<<"Step"<<}
voidSwap(int&a,int&b){//交换
intt;
t=a;
a=b;
b=t;
}
voidAssign(Node&node,intindex){//获取节点
for(inti=0;ifor(intj=0;j
node.digit[i][j]=node_v[index].digit[i][j];
}
intGetMinNode(){//获取启发值最小的节点
intdist=MAXNUM;
intloc;//thelocationofminimizenode
for(inti=0;iif(node_v[i].dist==MAXNUM)
continue;
elseif((node_v[i].dist+node_v[i].dep)loc=i;
dist=node_v[i].dist+node_v[i].dep;
}
}
returnloc;
}
boolisExpandable(Node&node){//判断是否可扩展
for(inti=0;iif(isEqual(i,node.digit))
returnfalse;
}
returntrue;
}
intDistance(Node&node,intdigit[][COL]){//计算距离
intdistance=0;
boolflag=false;
for(inti=0;ifor(intj=0;j
for(intk=0;kfor(intl=0;l
if(node.digit[i][j]==digit[k][l]){
distance+=abs(i-k)+abs(j-l);
flag=true;
break;
}
else
flag=false;
}
if(flag)
break;
}
returndistance;
}
intMinDistance(inta,intb){//二者取小
return(a
a:
b);
}
voidProcessNode(intindex){//展开节点
intx,y;
boolflag;
for(inti=0;ifor(intj=0;j
if(node_v[index].digit[i][j]==0){
x=i;y=j;
flag=true;
break;
}
elseflag=false;
}
if(flag)
break;
}
Nodenode_up;//上移操作
Assign(node_up,index);
intdist_up=MAXDISTANCE;
if(x>0){
Swap(node_up.digit[x][y],node_up.digit[x-1][y]);
if(isExpandable(node_up)){
dist_up=Distance(node_up,dest.digit);
node_up.index=index;
node_up.dist=dist_up;
node_up.dep=node_v[index].dep+1;
node_v.push_back(node_up);
}
}
Nodenode_down;//下移操作
Assign(node_down,index);
intdist_down=MAXDISTANCE;
if(x<2){
Swap(node_down.digit[x][y],node_down.digit[x+1][y]);
if(isExpandable(node_down)){
dist_down=Distance(node_down,dest.digit);
node_down.index=index;
node_down.dist=dist_down;
node_down.dep=node_v[index].dep+1;
node_v.push_back(node_down);
}
}
Nodenode_left;//左移操作
Assign(node_left,index);
intdist_left=MAXDISTANCE;
if(y>0){
Swap(node_left.digit[x][y],node_left.digit[x][y-1]);
if(isExpandable(node_left)){
dist_left=Distance(node_left,dest.digit);
node_left.index=index;
node_left.dist=dist_left;
node_left.dep=node_v[index].dep+1;
node_v.push_back(node_left);
}
}
Nodenode_right;//右移操作
Assign(node_right,index);
intdist_right=MAXDISTANCE;
if(y<2){
Swap(node_right.digit[x][y],node_right.digit[x][y+1]);
if(isExpandable(node_right)){
dist_right=Distance(node_right,dest.digit);
node_right.index=index;
node_right.dist=dist_right;
node_right.dep=node_v[index].dep+1;
node_v.push_back(node_right);
}
}
node_v[index].dist=MAXNUM;
}
intmain(){
intnumber;
cout<<"输入初始状态:
"<for(inti=0;ifor(intj=0;j
cin>>number;
src.digit[i][j]=number;
}
src.index=0;
src.dep=1;
cout<<"输入目标状态"<for(intm=0;mfor(intn=0;n
cin>>number;
dest.digit[m][n]=number;
}
node_v.push_back(src);
while
(1){
if(isEmptyOfOPEN()){
cout<<"找不到解!
"<return-1;
}
else{
intloc;//thelocationoftheminimizenode
loc=GetMinNode();
if(isEqual(loc,dest.digit)){
vectorrstep_v;
cout<<"初始状态:
"<cout<PrintSteps(loc,rstep_v);
cout<<"成功!
"<break;
}
else
ProcessNode(loc);
}
}
return0;
}
|
|
|
|
|
|
|
|