启发式搜索解决八数码问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include"stdio.h"
int goal[9]={1,2,3,8,0,4,7,6,5},sgoal[9];//goal为棋盘的目标布局,并用中间状态sgoal与之比较
struct Board
{
int pos[9];
int d,f,e;//d:深度;f:启发函数;e:记录前一次的扩展节点
};
struct NodeLink
{
Board boardstate;
NodeLink *parent;
NodeLink *previous;
NodeLink *next;
NodeLink *path;
};
//更新纪录八数码的状态
void setboard(int a[],int b[],int flag) //flag=0,写棋子;flag=1,写棋盘
{
for(int i=0;i<=8;i++)
if(flag)
a[b[i]]=i;
else
b[a[i]]=i;
}
//计算启发值的函数
int calvalue(int a[]) //不在位棋子数
{
int c=0;
for(int i=0;i<=8;i++)
if(a[i]!=goal[i])
if(goal[i]!=0)
c++;
return c;
}
//生成一个新节点的函数
NodeLink *makenode(NodeLink *TEM,int depth,int flag)
{
NodeLink *temp=new NodeLink;
for(int i=0;i<=8;i++)
temp->boardstate.pos[i]=TEM->boardstate.pos[i];
switch(flag)
{
case 1:
{
temp->boardstate.pos[0]--;
temp->boardstate.pos[sgoal[temp->boardstate.pos[0]]]++; //向左移break;
}
case 2:
{
temp->boardstate.pos[0]++;
temp->boardstate.pos[sgoal[temp->boardstate.pos[0]]]--; //向右移
break;
}
case 3:
{
temp->boardstate.pos[0]-=3;
temp->boardstate.pos[sgoal[temp->boardstate.pos[0]]]+=3; //向上移break;
}
case 4:
{
temp->boardstate.pos[0]+=3;
temp->boardstate.pos[sgoal[temp->boardstate.pos[0]]]-=3; //向下移break;
}
}
temp->boardstate.d=depth+1;
setboard(sgoal,temp->boardstate.pos,1);
temp->boardstate.f=temp->boardstate.d+calvalue(sgoal);
temp->boardstate.e=flag;
temp->parent=TEM;
return temp;
}
//把新节点加入OPEN队列
NodeLink *addnode(NodeLink *head,NodeLink *node) //把node插入到head链中{
NodeLink *TEM;
TEM=head;
head=node;
head->next=TEM;
head->previous=NULL;
if(TEM)
TEM->previous=head; //TEM已为空,无需操作
return head;
}
//求启发值最小的结点
NodeLink *minf(NodeLink *head)
{
NodeLink *min,*forward;
min=head;
forward=head;
while(forward)
{
if(min->boardstate.f>forward->boardstate.f)
min=forward;
forward=forward->next;
}
return min;
}
int main( )
{
int depth=0;
int source[9];
int i,j;
NodeLink *OPEN=new NodeLink;
NodeLink *TEMP,*TEM;
printf("请输入初始状态:\n");
for(i=0;i<9;i++)
scanf("%d",&source[i]);
setboard(source,OPEN->boardstate.pos,0);
OPEN->boardstate.d=depth;
OPEN->boardstate.e=0;
OPEN->boardstate.f=depth+calvalue(source);
OPEN->next=NULL;
OPEN->previous=NULL;
OPEN->parent=NULL;
while(OPEN)
{
TEMP=minf(OPEN); //求具有最小启发值的节点
setboard(sgoal,TEMP->boardstate.pos,1); //写棋盘
if(!calvalue(sgoal))
break;
if(TEMP!=OPEN) //如果不是第一个节点
{
TEMP->previous->next=TEMP->next;
TEMP->next->previous=TEMP->previous;
}
else//是第一个节点
{
if(OPEN->next) //如果还有节点
{
OPEN=OPEN->next;
OPEN->previous=NULL;
}
else OPEN=NULL; //否则置为空
}
if(TEMP->boardstate.pos[0]-1>=0&&TEMP->boardstate.e!=2) //防止棋子回到原状态 OPEN=addnode(OPEN,makenode(TEMP,depth,1));
if(TEMP->boardstate.pos[0]+1<=8&&TEMP->boardstate.e!=1)
OPEN=addnode(OPEN,makenode(TEMP,depth,2));
if(TEMP->boardstate.pos[0]-3>=0&&TEMP->boardstate.e!=4)
OPEN=addnode(OPEN,makenode(TEMP,depth,3));
if(TEMP->boardstate.pos[0]+3<=8&&TEMP->boardstate.e!=3)
OPEN=addnode(OPEN,makenode(TEMP,depth,4));
depth++;
}
if(OPEN) //如有解,则打印出解的步骤
{
printf("共需%d 步即可完成。
\n",depth);
TEMP->path=NULL;
while(TEMP->parent) //每次回溯父节点,生成路径
{
TEMP->parent->path=TEMP;
TEMP=TEMP->parent;
}
j=0;
while(TEMP->path)
{
setboard(sgoal,TEMP->boardstate.pos,1); printf("第%d步:\n",j);
for(i=0;i<=2;i++)
printf(" %d",sgoal[i]);
printf(" \n");
for(i=3;i<=5;i++)
printf(" %d",sgoal[i]);
printf("\n");
for(i=6;i<=8;i++)
printf(" %d",sgoal[i]);
printf("\n");
TEMP=TEMP->path;
j++;
}
setboard(sgoal,TEMP->boardstate.pos,1); printf("第%d步:\n",j);
for(i=0;i<=2;i++)
printf(" %d",sgoal[i]);
printf("\n");
for(i=3;i<=5;i++)
printf(" %d",sgoal[i]);
printf("\n");
for(i=6;i<=8;i++)
printf(" %d",sgoal[i]);
printf("\n");
}
else
printf("该问题无法求解!");
}。