A星算法求解8数码问题实验.docx
- 文档编号:8124577
- 上传时间:2023-01-29
- 格式:DOCX
- 页数:18
- 大小:106.32KB
A星算法求解8数码问题实验.docx
《A星算法求解8数码问题实验.docx》由会员分享,可在线阅读,更多相关《A星算法求解8数码问题实验.docx(18页珍藏版)》请在冰豆网上搜索。
A星算法求解8数码问题实验
实验三:
A*算法求解8数码问题实验
一、实验目的
熟悉与掌握启发式搜索的定义、估价函数与算法过程,并利用A*算法求解N数码难题,理解求解流程与搜索顺序、
二、实验内容
1、八数码问题描述
所谓八数码问题起源于一种游戏:
在一个3×3的方阵中放入八个数码1、2、3、4、5、6、7、8,其中一个单元格是空的、将任意摆放的数码盘(城初始状态)逐步摆成某个指定的数码盘的排列(目标状态),如图1所示
图1八数码问题的某个初始状态与目标状态
关于以上问题,我们能够把数码的移动等效城空格的移动。
如图1的初始排列,数码7右移等于空格左移。
那么关于每一个排列,估计的一次数码移动最多只有4中,即空格左移、空格右移、空格上移、空格下移。
最少有两种(当空格位于方阵的4个角时)。
因此,问题就转换成如何从初始状态开始,使空格经过最小的移动次数最后排列成目标状态。
2、八数码问题的求解算法
2、1盲目搜索
宽度优先搜索算法、深度优先搜索算法
2、2 启发式搜索
启发式搜索算法的基本思想是:
定义一个评价函数f,对当前的搜索状态进行评估,找出一个最有希望的节点来扩展、
先定义下面几个函数的含义:
f*(n)=g*(n)+h*(n)(1)
式中g*(n)表示从初始节点s到当前节点n的最短路径的耗散值;h*(n)表示从当前节点n到目标节点g的最短路径的耗散值,f*(n)表示从初始节点s经过n到目标节点g的最短路径的耗散值。
评价函数的形式可定义如(2)式所示:
f(n)=g(n)+h(n) (2)
其中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) (3)
成立,则称好h(x)为h*(x)的下界,它表示某种偏于保守的估计。
采纳h*(x)的下界h(x)为启发函数的A算法,称为A*算法、
针对八数码问题启发函数设计如下:
f(n)=d(n)+p(n)(4)
其中A*算法中的g(n)依照具体情况设计为d(n),意为n节点的深度,而h(n)设计为
是
图2A*算法流程图
p(n),意为放错的数码与正确的位置距离之与、
由于实际情况中,一个将牌的移动都是单步进行的,没有交换拍等如此的操作。
因此要把所有的不在位的将牌,移动到各自的目标位置上,至少要移动从她们各自的位置到目标位置的距离与这么多次,因此最有路径的耗散值可不能比该值小,因此该启发函数h(n)满足A*算法的条件。
3、A*算法流程图,如图2
4、A*算法总结
4、1,把起始状态添加到开启列表。
4、2,重复如下工作:
a) 寻找开启列表中f值最低的节点,我们称它为BESTNOE
b)把它切换到关闭列表中。
c) 对相邻的4个节点中的每一个
*假如它不在开启列表,也不在关闭列表,把它添加到开启列表中。
把BESTNODE作为这一节点的父节点。
记录这一节点的f与g值
*假如它已在开启或关闭列表中,用g值为参考检查新的路径是否更好。
更低的g值意味着更好的路径、假如如此,就把这一节点的父节点改为BESTNODE,同时重新计算这一节点的f与g值,假如保持开启列表的f值排序,改变之后需要重新对开启列表排序。
d)停止
把目标节点添加到关闭列表,这时候路径被找到,或者没有找到路径,开启列表差不多空了,这时候路径不存在、
4、3,保存路径、从目标节点开始,沿着每一节点的父节点移动直到回到起始节点、这就是求得的路径。
5、数据结构
采纳结构体来保存八数码的状态、f与g的值以及该节点的父节点;
structNode{
int s[3][3];//保存八数码状态,0代表空格
intf,g;//启发函数中的f与g值
structNode* next;
structNode*previous;//保存其父节点
};
6、实验结果,如图3所示
图3 A*算法求解八数码问题实验结果
7、源代码
//——--——-—-——-—--—-----———---———-—--—--—-————-—---—-———-——-----—-—-——-——---———-
//代码:
利用A*算法求解八数码问题、
//八数码问题的启发函数设计为:
f(n)=d(n)+p(n),其中A*算法中的g(n)依照具体情况设计为d(n),意为n节点的深度,而h(n)设计为p(n),意为放错的数码与正确的位置距离之与、
//后继结点的获取:
数码的移动等效为空格的移动。
首先判断空格上下左右的可移动性,其次移动空格获取后继结点。
//---————————--—-——---————-———---——--—-—-—-—--—-—--——---—----——--—-----———---——
#include〈stdio、h>
#include〈stdlib、h〉
#include〈math、h>
//八数码状态对应的节点结构体
struct Node{
ints[3][3];//保存八数码状态,0代表空格
intf,g;//启发函数中的f与g值
structNode* next;
structNode*previous;//保存其父节点
};
int open_N=0;//记录Open列表中节点数目
//八数码初始状态
intinital_s[3][3]={
2,8,3,
1,6,4,
7,0,5
};
//八数码目标状态
int final_s[3][3]={
1,2,3,
8,0,4,
7,6,5
};
//-———----—--—————-——————————-————-——-————-—-———-----—-—---—————---———-——-
//添加节点函数入口,方法:
通过插入排序向指定表添加
//—-——--—--—--————-—---——-——---—----—-—---—---—-—-——-————--——-—-—---————--
void Add_Node(struct Node*head,struct Node*p)
{
struct Node*q;
if(head—〉next)//考虑链表为空
{ q= head-〉next;
ﻩif(p-〉f ﻩﻩﻩp—>next=head—〉next; ﻩﻩhead->next= p; ﻩ} else{ ﻩ while(q-〉next)//考虑插入节点x,形如a<=x<=b ﻩ { ﻩif((q-〉f < p—〉f||q—〉f==p-〉f)&&(q->next—>f > p->f||q—〉next-〉f==p—>f)){ ﻩﻩﻩ p-〉next=q—>next; ﻩﻩﻩ q-〉next=p; ﻩ break; ﻩﻩﻩ} ﻩ q=q-〉next; } ﻩif(q-〉next==NULL)//考虑插入的节点值比链表最后一个元素的值更大 ﻩﻩq—>next = p; ﻩ } } else head->next=p; } //——--—--—-—————-—-———--—--——-——--—---—-——---—-—-—--—-—-----——-----——--—-— //删除节点函数入口 //——--—————--———————--—---—--————---—--——--——--—-—--——----——--——-——----——- void del_Node(structNode*head,structNode *p ) { structNode*q; q=head; while(q->next) { ﻩif(q—〉next==p){ ﻩ q-〉next= p->next; ﻩp-〉next=NULL; ﻩ if(q->next ==NULL)return; //free(p); } q=q—〉next; } } //--—-—--——-—--———------————-—-——-—-—-——--—————-——--—--——--—-—-—--———-—-—- //判断两个数组是否相等函数入口 //-——-——————---———-———-——-—--—-—--———-——-—-———-—--—-——-——-—-—-——--—----—-— intequal(ints1[3][3],ints2[3][3]) { inti,j,flag=0; for(i=0;i<3;i++) ﻩfor(j=0;j〈3 ;j++) ﻩﻩif(s1[i][j]! =s2[i][j]){flag=1;break;} if(! flag) ﻩreturn 1; else return0; } //——-—-—------———--——-----———-———---———--—---—-----——-—-——--——-—-—----——-— //判断后继节点是否存在于Open或Closed表中函数入口 //---—-—-—---—-—-——-—-———-———————-—-———--—-—-----—-—-——-—-—-——-————---—--— intexit_Node(struct Node*head,ints[3][3],structNode*Old_Node) { structNode*q=head-〉next; intflag =0; while(q) ﻩ if(equal(q—>s,s)){ ﻩﻩflag=1; ﻩﻩOld_Node—>next=q; ﻩ return 1;} ﻩ else q= q—>next; if(! flag)return0; } //——-------——----—-—--———----—--—-——-----—-------————---—-——-————------—-- //计算p(n)的函数入口 //其中p(n)为放错位的数码与其正确的位置之间距离之与 //具体方法: 放错位的数码与其正确的位置对应下标差的绝对值之与 //--———---——-——-—————--——--—-----——--——---———-——-——-—-—————-———-——--—----— intwrong_sum(ints[3][3]) { inti,j,fi,fj,sum=0; for(i=0 ;i<3; i++) ﻩfor(j=0;j〈3; j++) { ﻩfor(fi=0;fi<3; fi++) ﻩ for(fj=0;fj〈3;fj++) ﻩﻩif((final_s[fi][fj]== s[i][j])){ sum+=fabs(i—fi)+fabs(j—fj); ﻩ break; ﻩ } ﻩ ﻩ} returnsum; } //-—-—-———-------————-—---—-—---—--—--—--————-—--—------—-—-----———-—-—--— //获取后继结点函数入口 //检查空格每种移动的合法性,假如合法则移动空格得到后继结点 //———-—-—--—-——---—-—-—-—-———-———---———-—-—-——--———---—-——-—--—————------— intget_successor(struct Node*BESTNODE,intdirection, structNode*Successor)//扩展BESTNODE,产生其后继结点SUCCESSOR { int i,j,i_0,j_0,temp; for(i=0; i〈3;i++) for(j=0; j〈3; j++) ﻩSuccessor->s[i][j]= BESTNODE—〉s[i][j]; //获取空格所在位置 for(i=0;i<3;i++) for(j=0; j<3;j++) ﻩﻩif(BESTNODE->s[i][j]== 0){i_0=i;j_0=j;break;} switch(direction) { ﻩcase 0: if((i_0-1)>—1){ ﻩtemp =Successor-〉s[i_0][j_0]; ﻩﻩﻩ Successor—〉s[i_0][j_0]= Successor->s[i_0-1][j_0]; ﻩﻩSuccessor->s[i_0—1][j_0]=temp; ﻩﻩreturn 1; ﻩﻩ} ﻩ elsereturn 0; ﻩﻩﻩﻩ ﻩcase 1: if((j_0-1)〉—1){ ﻩﻩ temp =Successor->s[i_0][j_0]; ﻩﻩ Successor->s[i_0][j_0]=Successor—>s[i_0][j_0-1]; ﻩSuccessor—〉s[i_0][j_0—1]=temp; ﻩﻩﻩ return1; ﻩ} ﻩ else return0; ﻩcase2: if((j_0+1)<3){ ﻩﻩ temp=Successor—>s[i_0][j_0]; ﻩﻩSuccessor-〉s[i_0][j_0]=Successor-〉s[i_0][j_0+1]; ﻩﻩ Successor—〉s[i_0][j_0+1]= temp; ﻩﻩﻩreturn1; ﻩﻩ} elsereturn0; ﻩﻩﻩ ﻩ case3: if((i_0+1)〈3){ ﻩﻩ temp =Successor—>s[i_0][j_0]; ﻩﻩSuccessor->s[i_0][j_0] =Successor->s[i_0+1][j_0]; ﻩﻩﻩSuccessor-〉s[i_0+1][j_0]= temp; ﻩﻩ return1; ﻩﻩ } ﻩﻩ else return 0; ﻩﻩ } } //----—-----—---—---—-——--—----——---—-—-—--——-—---——--—-———-----—--——-—--— //从OPen表获取最佳节点函数入口 //—---—---—-———----——-—————-—-——--———-——-——-————---———-——---———-—-—-——-—-- struct Node*get_BESTNODE(struct Node*Open) { return Open—>next; } //-——-—--—-—-----—--——-—----—---——————--——--—---—-———------———--———--—--—— //输出最佳路径函数入口 //-—-—--—--——-—----——-———--———---------———-—--—————---——-—--——-—-—————---- voidprint_Path(struct Node*head) { structNode*q,*q1,*p; int i,j,count=1; p=(structNode*)malloc(sizeof(structNode)); //通过头插法变更节点输出次序 p—〉previous=NULL; q=head; while(q) { q1=q—>previous; q—〉previous= p-〉previous; p-〉previous = q; q =q1; } q=p-〉previous; while(q) { if(q==p->previous)printf(”八数码的初始状态: \n”); elseif(q—〉previous==NULL)printf(”八数码的目标状态: \n”); elseprintf("八数码的中间态%d\n”,count++); for(i=0;i<3; i++) for(j=0;j〈3; j++) ﻩ{ ﻩprintf(”%4d",q->s[i][j]); ﻩﻩif(j== 2)printf(”\n”); ﻩ } printf("f=%d, g=%d\n\n”,q-〉f,q->g); q= q->previous; } } //————--—---——-—-—-—--———----———------———-—--———-—----————--—--—-————-—--— //A*子算法入口: 处理后继结点 //-—-—-------——-----—---—--—-—————————-—----—---——-——---—---—---———-—————— voidsub_A_algorithm(structNode *Open, structNode*BESTNODE,structNode* Closed,struct Node *Successor) { structNode* Old_Node= (structNode*)malloc(sizeof(structNode)); Successor->previous= BESTNODE;//建立从successor返回BESTNODE的指针 Successor—>g =BESTNODE->g+ 1;//计算后继结点的g值 //检查后继结点是否已存在于Open与Closed表中,假如存在: 该节点记为old_Node,比较后继结点的g值与表中old_Node节点 //g值,前者小代表新的路径比老路径更好,将Old_Node的父节点改为BESTNODE,并修改其f,g值,后者小则什么也不做。 //即不存在Open也不存在Closed表则将其加入OPen表,并计算其f值 if(exit_Node(Open, Successor-〉s, Old_Node) ){ ﻩ if(Successor-〉g 〈Old_Node-〉g){ Old_Node-〉next-〉previous =BESTNODE;//将Old_Node的父节点改为BESTNODE ﻩ Old_Node->next->g=Successor-〉g;//修改g值 ﻩ Old_Node—>next-〉f=Old_Node—〉g + wrong_sum(Old_Node->s);//修改f值 ﻩﻩ//排序~~~~~~~~~~~~~~~~~~ ﻩﻩdel_Node(Open,Old_Node); ﻩﻩ Add_Node(Open,Old_Node); ﻩ} ﻩ } ﻩelse if( exit_Node(Closed,Successor—>s, Old_Node)){ if(Successor-〉g<Old_Node—〉g){ ﻩ Old_Node—>next->previous=BESTNODE; ﻩﻩOld_Node-〉next-〉g= Successor—〉g; ﻩ Old_Node—>next—>f =Old_Node->g +wrong_sum(Old_Node-〉s); ﻩﻩ//排序~~~~~~~~~~~~~~~~~~ ﻩﻩ del_Node(Closed,Old_Node); Add_Node(Closed,Old_Node); ﻩ} ﻩ } ﻩﻩ else{ ﻩﻩSuccessor—〉f=Successor->g +wrong_sum(Successor—〉s); ﻩﻩﻩ Add_Node(Open, Successor); ﻩﻩ open_N++; ﻩﻩ} } //-——--———-—---—-—-—---———--—-—-———-—--————-—----—--———-—------——---—-———— //A*算法入口 //八数码问题的启发函数为: f(n)=d(n)+p(n) //其中A*算法中的g(n)依照具体情况设计为d(n),意为n节点的深度,而h(n)设计为p(n), //意为放错的数码与正确的位置距离之与 //-——-—---——-—-—---—-——-—--———--—-—-—---——--——-———---—--—---—--——--——--—-— void A_algorithm(structNode *Open, structNode*Closed)//A*算法 { inti,j; struct Node*BESTNODE, *inital,*Successor; inital = (structNode*)malloc(sizeof(struct Node)); //初始化起始节点 for(i=0;i<3;i++) ﻩ for(j=0;j<3;j++) ﻩinital—〉s[i][j] = inital_s[i][j]; inital->f =wrong_sum(inital_s); inital-〉g=0; inital—〉previous= NULL; inital—〉next =NULL; Add_Node(Open,inital);//把初始节点放入OPEN表 open_N++; while(1) { ﻩif(open_N ==0){printf("failure! ”); return;} else { ﻩﻩ BESTNODE=get_BESTNODE(Open);//从OPEN表获取f值最小的BESTNODE,将其从OPEN表删除并加入CLOSED表中 ﻩﻩdel_Node(Open, BESTNODE); ﻩﻩopen_N—-; ﻩ ﻩ Add_Node(Closed,BESTNODE); ﻩﻩ if(equal(BESTNODE-〉s,final_s)){//判断BESTNODE是否为目标节点 ﻩﻩﻩprintf("success! \n"); ﻩﻩﻩ print_Path(BESTNODE); ﻩﻩﻩ return; ﻩﻩ} ﻩ//针对八数码问题,后继结点Successor
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 求解 数码 问题 实验
![提示](https://static.bdocx.com/images/bang_tan.gif)