A星算法求解8数码问题实验Word下载.docx
《A星算法求解8数码问题实验Word下载.docx》由会员分享,可在线阅读,更多相关《A星算法求解8数码问题实验Word下载.docx(18页珍藏版)》请在冰豆网上搜索。
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 <
head—>next->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;
for(j=0;
j<
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;
for(j=0;
ﻩ{
ﻩ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—>
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;
ﻩ for(j=0;
j<
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