人工智能导论实验报告模板.docx
《人工智能导论实验报告模板.docx》由会员分享,可在线阅读,更多相关《人工智能导论实验报告模板.docx(16页珍藏版)》请在冰豆网上搜索。
人工智能导论实验报告模板
《人工智能导论》上机实验
八数码问题求解
专业班级:
姓名:
学号:
指导教师:
基于人工智能的状态空间搜索策略研究
——八数码问题求解
一、实验软件
VC6.0编程语言或其它编程语言
二、实验目的
1.熟悉人工智能系统中的问题求解过程;
2.熟悉状态空间的盲目搜索和启发式搜索算法的应用;
3.熟悉对八数码问题的建模、求解及编程语言的应用。
三、需要的预备知识
1.熟悉VC6.0编程语言;
2.熟悉状态空间的宽度优先搜索、深度优先搜索和启发式搜索算法;
3.熟悉计算机语言对常用数据结构如链表、队列等的描述应用;
4.熟悉计算机常用人机接口设计。
四、实验数据及步骤
1.实验内容
八数码问题:
在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
例如:
2
5
4
1
2
3
3
7
8
4
1
8
6
7
6
5
(a)初始状态(b)目标状态
图1八数码问题示意图
请任选一种盲目搜索算法(深度优先搜索或宽度优先搜索)或任选一种启发式搜索方法(A算法或A*算法)编程求解八数码问题(初始状态任选),并对实验结果进行分析,得出合理的结论。
2.实验步骤
(1)分析算法基本原理和基本流程;
(2)确定对问题描述的基本数据结构,如Open表和Closed表等;
(3)编写算符运算、目标比较等函数;
(4)编写输入、输出接口;
(5)全部模块联调;
(6)撰写实验报告。
五、实验报告要求
所撰写的实验报告必须包含以下内容:
1.算法基本原理和流程框图;
2.基本数据结构分析和实现;
3.编写程序的各个子模块,按模块编写文档,含每个模块的建立时间、功能、输入输出参数意义和与其它模块联系等;
4.程序运行结果,含使用的搜索算法及搜索路径等;
5.实验结果分析;
6.结论;
7.提供全部源程序及软件的可执行程序。
6、操作实现
该设计采用启发式搜索方法编写程序。
该程序是自动产生一组随机数(0至8)填在3×3数组中,然后对该组随机数进行评估,距离目标状态的差距,具体内容如下:
1、启发函数设定
由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零,因此可以把数码不同的位置个数作为标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息来扩展节点的选择,减少搜索范围,提高搜索速度。
2、数据结构与算法设计
数码结构体
typedefstructnode//八数码结构体
{
intform[N][N];//数码组
intevalue;//评估值,差距
intudirec;//所屏蔽方向,防止往回推到上一状态,1上2下3左4右
structnode*parent;//父节点
}Graph;
Graph*Qu[MAX];//队列
Graph*St[MAX];//堆栈
搜索过程:
(搜索采用广度搜索方式,利用待处理队列辅助,逐层搜索(跳过劣质节点))
a、把初始数码组压入队列;
b、从队列中取出一个数码组节点;
c、扩展子节点,即从上下左右四个方向移动空格,生成相应子节点:
d、对子节点数码组作评估,是否为优越节点,即其评估值是否小于等于其父节点加一,是则将其压入队,否则抛弃。
e、判断压入队的子节点数码组(优越点)的评估值,为零则表示搜索完成,退出搜索;
f、跳到步骤2;
3、程序结构图
4、程序流程框图
voidPrint(Graph*The_graph)
2
typedefstructnode
1
intEvaluate(Graph*The_graph,Graph*End_graph)
3
Graph*Move(Graph*The_graph,intDirect,intCreateNew_graph)
4
Graph*CR_BeginGraph(Graph*The_graph)
6
Graph*Search(Graph*Begin,Graph*End)
5
voidmain()
7
5、源程序
#include
#include
#include
#defineN3//数码组大小
#defineMax_Step30//最大搜索深度
#defineMAX50
typedefstructnode//八数码结构体
{
intform[N][N];//数码组
intevalue;//评估值,差距
intudirec;//所屏蔽方向,防止往回推到上一状态,1上2下3左4右
structnode*parent;//父节点
}Graph;
Graph*Qu[MAX];//队列
Graph*St[MAX];//堆栈
/*打印数码组*/
voidPrint(Graph*The_graph)
{
inti,j;
if(The_graph==NULL)
printf("图为空\n");
else
{
printf("-----------------------------------------\n");
for(i=0;i{
printf("|\t");
for(j=0;j{
printf("%d\t",The_graph->form[i][j]);//遍历打印
}
printf("\t|\n");
}
printf("|\t\t\t\t差距:
%d\t|\n",The_graph->evalue);//差距显示
printf("-----------------------------------------\n");
}
}
/*估价函数*/
intEvaluate(Graph*The_graph,Graph*End_graph)
{
intvalue=0;//差距数
inti,j;
for(i=0;i{
for(j=0;j{
if(The_graph->form[i][j]!
=End_graph->form[i][j])//遍历数码组比较差距
value++;
}
}
The_graph->evalue=value;
returnvalue;
}
/*移动数码组*/
Graph*Move(Graph*The_graph,intDirect,intCreateNew_graph)
{
Graph*New_graph;
intHasGetBlank=0;//是否获取空格位置
intAbleMove=1;//是否可移动
inti,j,t_i,t_j,x,y;
for(i=0;i{
for(j=0;j{
if(The_graph->form[i][j]==0)
{
HasGetBlank=1;
break;
}
}
if(HasGetBlank)
break;
}
//printf("空格位置:
%d,%d\n",i,j);
t_i=i;t_j=j;
switch(Direct)//移动空格
{
case1:
//上
t_i--;
if(t_i<0)
AbleMove=0;
break;
case2:
//下
t_i++;
if(t_i>=N)
AbleMove=0;
break;
case3:
//左
t_j--;
if(t_j<0)
AbleMove=0;
break;
case4:
//右
t_j++;
if(t_j>=N)
AbleMove=0;
break;
};
if(!
AbleMove)//不可以移动则返回原节点
{
returnThe_graph;
}
if(CreateNew_graph)
{
New_graph=(Graph*)malloc(sizeof(Graph));//生成节点
for(x=0;x{
for(y=0;yNew_graph->form[x][y]=The_graph->form[x][y];//复制数码组
}
}
else
{
New_graph=The_graph;
}
/*移动后*/
New_graph->form[i][j]=New_graph->form[t_i][t_j];
New_graph->form[t_i][t_j]=0;
returnNew_graph;
}
/*搜索函数*/
Graph*Search(Graph*Begin,Graph*End)
{
Graph*g1,*g2,*g;
intStep=0;//深度
intDirect=0;
inti;
intfront,rear;
front=rear=-1;//队列初始化
g=NULL;
rear++;//入队
Qu[rear]=Begin;
while(rear!
=front)//队不空
{
front++;//出队
g1=Qu[front];
//printf("开始第%d个图:
\n",front);
//Print(g1);
for(i=1;i<=4;i++)//分别从四个方向推导出新子节点
{
Direct=i;
if(Direct==g1->udirec)//跳过屏蔽方向
continue;
g2=Move(g1,Direct,1);//移动数码
if(g2!
=g1)//数码是否可以移动
{
Evaluate(g2,End);//对新节点评估
//printf("开始产生的第%d个图:
\n",i);
//Print(g2);
if(g2->evalue<=g1->evalue+1)//是否为优越节点
{
g2->parent=g1;
switch(Direct)//设置屏蔽方向,防止往回推
{
case1:
g2->udirec=2;break;
case2:
g2->udirec=1;break;
case3:
g2->udirec=4;break;
case4:
g2->udirec=3;break;
}
rear++;
Qu[rear]=g2;//存储节点到待处理队列
if(g2->evalue==0)//为0则,搜索完成
{
g=g2;
i=5;
}
}
else
{
free(g2);//劣质节点抛弃
g2=NULL;
}
}
}
Step++;//统计深度
if(Step>Max_Step)
returnNULL;
if(g!
=NULL)
break;
}
returng;
}
/*初始化一个八数码结构体*/
Graph*CR_BeginGraph(Graph*The_graph)
{
intM=10;//随机移动步数
intDirect;
inti,x,y;
Graph*New_graph;
New_graph=(Graph*)malloc(sizeof(Graph));//生成节点
for(x=0;x{
for(y=0;yNew_graph->form[x][y]=The_graph->form[x][y];//复制数码组
}
for(i=0;i{
Direct=rand()%4;
//printf("%d\n",Direct);
New_graph=Move(New_graph,Direct,0);
}
New_graph->evalue=0;
New_graph->udirec=0;
New_graph->parent=NULL;
//Print(New_graph);
returnNew_graph;
}
/*主函数*/
voidmain()
{
/*GraphBegin_graph={
{{2,8,3},{1,0,4},{7,6,5}},0,0,NULL
};*/
/*GraphBegin_graph={
{{2,0,1},{4,6,5},{3,7,8}},0,0,NULL
};*/
/*目标数码组*/
GraphEnd_graph={
{{1,2,3},{8,0,4},{7,6,5}},0,0,NULL
};
Graph*G,*P;
/*初始数码组*/
Graph*Begin_graph;
inttop=-1;
Begin_graph=CR_BeginGraph(&End_graph);//随机产生初始数码组
Evaluate(Begin_graph,&End_graph);//对初始数码组评估
printf("初始数码组:
\n");
//printf("udirec:
%d\tparent:
%d\n",Begin_graph->udirec,Begin_graph->parent);
Print(Begin_graph);
printf("目标数码组:
\n");
Print(&End_graph);
/*图搜索*/
G=Search(Begin_graph,&End_graph);
//Print(G);
/*打印*/
if(G)
{
//把路径倒序
P=G;
//压栈
while(P!
=NULL)
{
top++;
St[top]=P;
P=P->parent;
}
printf("\n<<<<<<<<<<<<<<<<<搜索结果>>>>>>>>>>>>>>>>\n");
/*弹栈打印*/
while(top>-1)
{
P=St[top];
top--;
Print(P);
}
printf("\n<<<<<<<<<<<<<<<<<<完成!
>>>>>>>>>>>>>>>>>>\n");
}
else
printf("搜索不到结果.深度为%d\n",Max_Step);
}//设计了搜索深度范围,防止队列内存越界
6、运行结果
七、总结
以上算法对一些简单的八数码问题是解决了,但对于复杂的八数码问题还是无能为力。
当中采用了屏蔽方向,虽然能有效地防止了往回搜索(节点的回推),但没能有效防止循环搜索,所以不能应用于复杂度较大的八数码问题。