八数码难题的搜索求解演示.docx
- 文档编号:28584441
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:15
- 大小:91.35KB
八数码难题的搜索求解演示.docx
《八数码难题的搜索求解演示.docx》由会员分享,可在线阅读,更多相关《八数码难题的搜索求解演示.docx(15页珍藏版)》请在冰豆网上搜索。
八数码难题的搜索求解演示
人工智能实验报告
学
院:
信息科学与工程学院
班
级:
自动化0901班
学
号:
06
姓
名:
孙锦岗
指导老师:
刘丽珏
日
期:
2011年12月20日
一、实验名称、目的及内容
实验名称:
八数码难题的搜索求解演示
实验目的:
加深对图搜索策略概念的理解,掌握搜索算法。
实验内容要求:
以八数码难题为例演示广度优先或深度优先搜索、A算法(本实
验使用的是广度优先搜索)的搜索过程,争取做到直观、清晰地演示算法。
八数码难题:
在3X3方格棋盘上,分别放置了标有数字123,4,5,6,7,8的八张牌,初始状态SO,目标状态如图所示,可以
使用的操作有:
空格上移,空格左移,空格右移,空格下移。
试编一程序实现这一搜索过程。
二、实验原理及基本技术路线图
实验原理:
八数码问题中,程序产生的随机排列转换成目标共有两种可能,而且这两种不可能同时成立,也就是奇数排列和偶数排列。
我们可以把一个随机排列的数组从左到右从上到下用一个数组表示,例如{8,
7,1,5,2,6,3,4,0}其中0代表空格。
它在奇序列位置上。
在这个数组中我们首先计算它能够重排列出来的结果,公式就是:
E(F(X))=Y,其中F(X),就是一个数他前面比这个数小的数的个数,Y为奇数和偶数个有一种解法。
那么上面的数组我们就可以解出它的结果。
数据结构:
本实验使用的数据结构是队列,应用队列先进先出的特点来实现对节点的保存和扩展。
首先建立一个队列,将初始结点入队,并设置队列头和尾指,然后取出队列(头指针所指)的结点进行扩展,从它扩展出子结点,并将这些结点按扩展的顺序加入队列,然后判断扩展出的新结点与队列中的结点是否重复,如果重复则,否则记录其父结点,并将它加入队列,更新队列尾指针,然后判断扩展出的结点是否是目标结点,如果是则显示路径,程序结束。
否则如果队列头的结点可以扩展,直接返回第二步。
否则将队列头指针指向下一结点,再返回第二步,知道扩展出的结点是目标结点结束,并显示路径。
算法分析:
九宫问题的求解方法就是交换空格(0)位置,直至到达目标位置为止。
如图所示:
因此可知:
九宫的所以排列有9!
种,也就是362880种排法,数据量是非常大的,我使用广度搜索,需要记住每一个结点的排列形式,要是用数组记录的话会占用很多的内存,我们把数据进行适当的压缩。
使用DWORD形式保存,压缩形式是每个数字用3位表示,这样就是3X9=27个字节,由于8的二进制表示形式1000,不能用3位表示,我使用了一个小技巧就是将8表示位000,然后用多出来的5个字表示8所在的位置,就可以用DWORD表示了。
用移位和或操作将数据逐个移入,比乘法速度要快点。
定义了几个结果来存储遍历到了结果和搜索完成后保存最优路径。
算法描述:
过程BREADTH-SEARCH
(1)G:
二GO(GO二s),OPEN:
=(s),CLOSE:
=();
(2)LOOP:
IFOPEN=()THENEXIT(FAIL);
(3)N:
=FIRST(OPEN);
(4)IFGOAL(n)THENEXIT(SUCCESS);
(5)RENMOVE(n,OPEN),ADD(n,CLOSED);
(6)EXPAND(n^{mi},G:
=ADD(mi,G);
(7)结点放在OPENS的后面,使深度浅的结点可优先扩展。
广度优先搜索的源代码如下:
voidBfs()
{queue
(org);
HashTable[]=-1;
while(NOT())
{
Mapnode=();
();
for(intk=0;k<4;k++)
{
Maptmp=node;
=+derection[k];
if<0||>8||(k>1&&/3!
=/3))
continue;
=HashValue(node,k);
if(0!
=HashTable[])continue;
[]=[];
建立一个队列,将初始结点入队,并设置队列头和尾指
验步骤
(1)运行MicrosoftVisualC++软件,新建工作空间,
得文档。
(2)输入源程序代码,进行编译,调试运行
(3)运行结果,按提示要求输入1—8这八个数,进行程序测验
2.实验源程序
#inelude<>
#inelude<>
#inelude<>
#inelude
#inelude
usingnamespaeestd;
#defineHashTableSize362881
#defineNOT!
#defineUP0
#defineDOWN1
#defineLEFT2
#defineRIGHT3
#defineBitehar
typedefstruetmaps
{
Bitdetail[9];
intmyindex;//记录自己节点在hash表中的位置
Bitposition;//记录空格(0)在序列中的位置
}Map,*PMap;
Maporg;//初始状态
intEndlndex;//目标,上移,下移,左移,右移
intconstderection[4]={-3,3,-1,1};
//可移动的四个方向
intconstFactorial[9]={40320,5040,720,120,24,6,
2,1,1};
intHashTable[HashTableSize]二{0};
//hash表,其中记录的是上一个父节点对应的位置
/****八数码的输入(在这里不做任何输入检查,均认为输入数据是
正确的)***/
voidinput()
{
inti,j;
intsum,count,index;
\for(i=0;i<9;i++)
{
scanf("%1d",&[i]);
[i]||=i);
}
for(i=0;i<9;i++)II计算逆序
{
if(0==[i])
continue;
for(j=0;j
sum+=(0!
=[j]&&[j]<[i]);
}
for(i=0,index=0;i<9;i++)
//计算初始状态的hash值
{
for(j=0,count=0;j
count+=[j]>[i];
index+=Factorial][i]]*count;
}
=index+1;
Endindex=sum%2?
161328:
322561;//目标状态的hash值
return;
}
/***hash值的计算*Parent:
父状态的hash值*direct:
移动的方向**/
inlineintHashValue(Map&Parent,int&direct)
{
inti=;
intnewindex=;
Bit*p=;
switch(direct)
{
caseUP:
{
newindex-二3*40320;
newindex+=(p[i-2]>p[i-3])?
(Factorial]p[i-3]]):
(-Factorial]p[i-2]]);
-3])?
/newindex+=(p[i-1]>p[i
(Factorial]p[i-3]]):
(-Factorial]p[i-1]]);break;
}
caseDOWN:
{
newindex+=3*40320;
\newindex-二(p[i+2]>p[i+3])?
(Factorial]p[i+3]]):
(-Factorial]p[i+2]]);
newindex-二(p]i+1]>p]i+3])?
(Factorial]p]i+3]]):
(-Factorial]p]i+1]]);break;
}
caseLEFT:
returnnewindex-40320;break;caseRIGHT:
returnnewindex+40320;break;
returnnewindex;
}
/****广度优先搜索***/
voidBfs()
{
queue
(org);
HashTable[]=-1;
while(NOT())
{
Mapnode=();
();
for(intk=0;k<4;k++)
{
\Maptmp=node;
=+derection[k];
if<0||>8||(k>1&&/3!
=/3))
continue;
=HashValue(node,k);
if(0!
=HashTable[])continue;
[]=[];
//移动空格
[]=0;
HashTable[]=;
//状态记录到hashtable中
if(==Endlndex)return;
(tmp);
}
}
return;
}
/****通过hash表中记录的进行查找路径***/
voidFindPath()
{
intnowindex;
intcount=0;
intnixu[9],result[9];
inti,j,k;
stack
(Endlndex);
nowindex=Endlndex;
while(-1!
=HashTable[nowindex])
{
(HashTable[nowindex]);
nowindex=HashTable[nowindex];}
printf("共需:
%d步\n",()-1);
getchar();
while(NOT())
{
nowindex=()-1;
();
//计算出逆序
//根据逆序计算排列
for(i=0;i<9;i++)
{
nixu[i]=nowindex/Factorial]i];
nowindex%=Factorial]i];
}
memset(result,-1,9*sizeof(int));
for(i=0;i<9;i++)
{
for(j=0,k=nixu[i];j<9;j++)
{
if(result[j]==-1)k--;
if(k<0)break;
}result[j]=i;
}
for(i=0;i<9;i++)
{
printf("%3d",result[i]);
if(2==i%3)printf("\n");
}
if(0!
=())
{
printf("\nJ第%d^\n",++count);
getchar();
}
}
printf("\nTheEnd!
\n");
return;
}
intmain()
{
input();//输入要排序的序列0--8
longtime二GetTickCount();
Bfs();
printf("计算用时:
%dMS\n",GetTickCount()-time);
FindPath();
return0;//返回结果
}
五、实验过程原始记录(测试数据、图表、计算等)
结果一:
分析:
此测试数据中的o位于奇序列中,故结果执行后为图示的结果
实验结果二:
1C:
,.卿ir曲卅負5庐址eJ2\Deoug\T'
2
6
3
1
S
4
7
E
5
第珍
a
2
3
1
4
7
6
5
I
第啡
1
2
3
a
8
4
7
b
第5步
1
2
3
3
0
4
?
£
£
The
End!
(Press且nykeytocontinue
w
J
分析:
此测试数据中的0位于偶序列中,故结果如图所示六、实验结果、分析和结论
由上面的结果,通过和其它的算法比较,我得出了以下结论对广度优先法进行归纳:
广度优先搜索法在有解的情形总能保证搜索到最短路经,也就是
移动最少步数的路径。
但广度优先搜索法的最大问题在于搜索的结点数量太多,因为在广度优先搜索法中,每一个可能扩展出的结点都是搜索的对象。
随着结点在搜索树上的深度增大,搜索的结点数会很快增长,并以指数形式扩张,从而所需的存储空间和搜索花费的时间也会成倍增长。
在进行广度搜索时候,将父结点所在的数组索引记录在子结点中了,所以得到目标排列的时候,我们只要从子结点逆向搜索就可以得到最优搜索路径了。
用变量m_iPathsize来记录总步数
通过这次实验我认识到了人工智能的一个典型的应用,也让我在一定程度上了解了人工智能的发展。
当然也发现自己的许多不足,真的是书到用时方恨少啊,以后还得多动手了,而不只是掌握课本知识。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数码 难题 搜索 求解 演示