程序环境:
运行环境:Windows xp
使用工具:Vc++6.0
启发式搜索简介:
启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径,提高了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。
它把到达节点的耗散g(n)和从该节点到目标节点的消耗h(n)结合起来对节点进行评价:f(n)=g(n)+h(n)
A*算法简介:
A*算法就是对估价函数加上一些限制后得到的一种启发式搜索算法。
其搜索过程可能描述如下:
(1)把初始节点S0放入Open表中,f(S0)=g(S0)+h(S0);
(2)如果Open表为空,则问题无解,失败退出;
(3)把Open表的第一个节点取出放入Closed表,并记该节点为n;
(4)考察节点n是否为目标节点。若是,则找到了问题的解,成功退出;
(5)若节点n不可扩展,则转到第(2)步;
(6)扩展节点n,生成子节点ni(i=1,2,……),计算每一个子节点的估价值f(ni) (i=1,2,……),并为每一个子节点设置指向父节点的指针,然后将这些子节点放入Open表中;
(7)根据各节点的估价函数值,对Open表中的全部节点按从小到大的顺序重新进行排序;
(8)转第(2)步。
图解:
代码:
如若代码有问题或有更为严重的错误请不吝赐教。
//八数码(九宫格)、拼图游戏???
/*==============================================================================
八数码问题的未找到路径时的条件是什么?
是否为 OPEN 表为空时还未找到路径即为无解条件
如此的话,运算量太大(此题最大为9!个),本机配置根本无法运行到最后-_-!(所以不知道是否正确)
==============================================================================*/
#include
#include
#include
#define MAX_NODESIZE 362880 //9的阶乘9!=362880
typedef struct node{ //八数码结构体
int a[3][3];//节点状态
//空格下标
int i_0;
int j_0;
//启发信息
int d; //搜索深度
int w; //各棋子不在正确位置的数目
int f; //总代价
struct node *father; //指向父节点指针
}node,*p_node;
typedef struct list //顺序表结构体
{
p_node a[MAX_NODESIZE];
long length;
}list,*p_list;
//static int s0[3][3]={8,2,3,1,0,4,7,6,5}; //初始结点
static int s0[3][3]={2,8,3,1,0,4,7,6,5}; //初始结点
/*
2 8 3
1 0 4
7 6 5
*/
static int sg[3][3]={1,2,3,8,0,4,7,6,5}; //目标结点
/*
1 2 3
8 0 4
7 6 5
*/
p_node s_0=(p_node) malloc(sizeof(node)); //初始节点
p_node s_g=(p_node) malloc(sizeof(node)); //目标节点
p_list OPEN =(p_list) malloc (sizeof(list)); //OPEN表
p_list CLOSED=(p_list) malloc (sizeof(list)); //CLOSE表
int w(p_node s); //计算各棋子不在正确位置的数目
int f(p_node s); //估价函数
void init_node(); //初始化
void out_node(p_node s); //输出八数码
void list_reverse(p_node &p); //将链表逆序
void out_list(p_list &l); //输出OPEN表
bool search_list(p_list &l,p_node s); //对表进行查找,成功返回true
void sort_list(p_list &l); //对OPEN表进行排序(按f从小到大)
void add_list(p_list &l,p_node s); //加入结点到OPEN表中或CLOSE表中
void copy_node(p_node s1,p_node &s2); //生成新的结点(将s2赋值给s1)
void delete_list(p_list &l); //从OPEN表或CLOSE中删除结点
bool is_equal(p_node s1,p_node s2); //判断两节点是否相等
bool up_mov(p_node &s); //空格上移
bool down_mov(p_node &s); //空格下移
bool left_mov(p_node &s); //空格左移
bool right_mov(p_node &s); //空格右移
void move(p_node s); //移动父节点并加入未探索表中(扩展结点)
int main()
{
init_node();
printf("\n程序求解过程如下:\n");
printf("=========================================================\n\n");
while(OPEN->length!=0 && CLOSED->length<=1000) //最多循环次数1000
{
p_node n=OPEN->a[0]; //---------------把Open表的第一个节点取出放入Closed表,并记该节点为n
delete_list(OPEN);
if(is_equal(n,s_g)) //考察节点n是否为目标节点。若是,则找到了问题的解,成功退出;亦可换成 if(w(n)==0){...}
{
list_reverse(n);
list_reverse(n);
list_reverse(n);
while(n)
{
printf("第 %d 步:\n",n->d+1);
out_node(n);
n=n->father;
}
break;
}
add_list(CLOSED,n);
move(n);//扩展结点n
sort_list(OPEN);
// out_list(OPEN);
}
if(OPEN->length==0 || CLOSED->length>1000)
{
printf("\n从初始结点无法到达目标结点!\n\n");
}
return 0;
}
int f(p_node s) //估价函数
{
return (s->d+s->w);
}
void out_node(p_node s) //输出八数码
{
printf("-------------------");
printf(" x=%d,y=%d\n",s->i_0,s->j_0);
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
printf("%5d",s->a[i][j]);
}
printf("\n");
}
printf("-------------------");
printf(" d=%d,w=%d; f=%d\n\n\n",s->d,s->w,s->f);
}
void out_list(p_list &l) //输出OPEN表
{
printf("****************************************************************\n");
for(int i=0;ilength;i++)
{
out_node(l->a[i]);
}
printf("****************************************************************\n");
}
int w(p_node s) //计算各棋子不在正确位置的数目
{
int w=0;
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
if (s->a[i][j]!=sg[i][j])
{
w++;
}
}
}
if (s->a[1][1]==sg[1][1])
{
w+=1;
}
return w-1;
}
bool left_mov(p_node &s) //空格左移
{
int x=s->i_0,y=s->j_0;
if (y==0)
{
return false;
}
int t;
t=s->a[x][y];
s->a[x][y]=s->a[x][y-1];
s->a[x][y-1]=t;
--s->j_0;
return true;
}
bool right_mov(p_node &s) //空格右移
{
int x=s->i_0,y=s->j_0;
if (y==2)
{
return false;
}
int t;
t=s->a[x][y];
s->a[x][y]=s->a[x][y+1];
s->a[x][y+1]=t;
++s->j_0;
return true;
}
bool up_mov(p_node &s) //空格上移
{
int x=s->i_0,y=s->j_0;
if (x==0)
{
return false;
}
int t;
t=s->a[x][y];
s->a[x][y]=s->a[x-1][y];
s->a[x-1][y]=t;
--s->i_0;
return true;
}
bool down_mov(p_node &s) //空格下移
{
int x=s->i_0,y=s->j_0;
if (x==2)
{
return false;
}
int t;
t=s->a[x][y];
s->a[x][y]=s->a[x+1][y];
s->a[x+1][y]=t;
++s->i_0;
return true;
}
bool is_equal(p_node s1,p_node s2) //判断两节点是否相等
{
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
if (s1->a[i][j]!=s2->a[i][j])
{
return false;
}
}
}
return true;
}
void copy_node(p_node s1,p_node &s2) //生成新的结点(将s2赋值给s1)
{
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
s1->a[i][j]=s2->a[i][j];
}
}
s1->i_0=s2->i_0;
s1->j_0=s2->j_0;
s1->d=s2->d;
s1->w=s2->w;
s1->f=s2->f;
s1->father=s2->father;
}
void add_list(p_list &l,p_node s) //加入结点到OPEN表中或CLOSE表中
{
l->a[l->length++]=s;
}
void delete_list(p_list &l) //从OPEN表或CLOSE中删除结点
{
for (int i=0;ilength;i++)
{
l->a[i]=l->a[i+1];
}
l->length--;
}
bool search_list(p_list &l,p_node s)//对表进行查找,成功返回true
{
for(int i=0;ilength;i++)
{
if(is_equal(l->a[i],s))
return true;
}
return false;
}
void move(p_node s)//移动父节点并加入未探索表中(扩展结点)
{
p_node p1=(p_node) malloc(sizeof(node));
p_node p2=(p_node) malloc(sizeof(node));
p_node p3=(p_node) malloc(sizeof(node));
p_node p4=(p_node) malloc(sizeof(node));
copy_node(p1,s);
copy_node(p2,s);
copy_node(p3,s);
copy_node(p4,s);
p1->father=s;
p2->father=s;
p3->father=s;
p4->father=s;
//如果能够移动且在CLOSED表中不存在,则加入OPEN表中
if(left_mov(p1) && !is_equal(p1,p1->father) && !search_list(CLOSED,p1) && !search_list(OPEN,p1))
{
add_list(OPEN,p1);
p1->d+=1;
p1->w=w(p1);
p1->f=f(p1);
}
else
{
free(p1);
}
if(right_mov(p2) && !is_equal(p2,p2->father) && !search_list(CLOSED,p2) && !search_list(OPEN,p2))
{
add_list(OPEN,p2);
p2->d+=1;
p2->w=w(p2);
p2->f=f(p2);
}
else
{
free(p2);
}
if(up_mov(p3) && !is_equal(p3,p3->father) && !search_list(CLOSED,p3) && !search_list(OPEN,p3))
{
add_list(OPEN,p3);
p3->d+=1;
p3->w=w(p3);
p3->f=f(p3);
}
else
{
free(p3);
}
if(down_mov(p4) && !is_equal(p4,p4->father) && !search_list(CLOSED,p4) && !search_list(OPEN,p4))
{
add_list(OPEN,p4);
p4->d+=1;
p4->w=w(p4);
p4->f=f(p4);
}
else
{
free(p4);
}
}
void sort_list(p_list &l) //对OPEN表进行排序,插入法排序(按f从小到大)
{
p_node t=(p_node) malloc (sizeof(node));
for(int i=1;ilength;i++)
{
if(l->a[i]->f < l->a[i-1]->f)
{
copy_node(t,l->a[i]);
for(int j=i;j>0;j--)
{
copy_node(l->a[j],l->a[j-1]);
}
copy_node(l->a[j],t);
}
}
}
void list_reverse(p_node &p) //将链表逆序
{
p_node p_pre,p_suc;
p_pre=NULL;
p_suc=p->father;
while(p)
{
p->father=p_pre;
p_pre=p;
if(p_suc == NULL)
{
break;
}
p=p_suc;
p_suc=p_suc->father;
}
}
void init_node() //初始化
{
//---------------------------------------初始化初始结点
for (int i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
s_0->a[i][j]=s0[i][j];
if(s_0->a[i][j] == 0)
{
s_0->i_0=i;
s_0->j_0=j;
}
}
}
s_0->d=0;
s_0->father=NULL;
s_0->w=w(s_0);
s_0->f=f(s_0);
//---------------------------------------初始化目标结点
for (i=0;i<3;i++)
{
for (int j=0;j<3;j++)
{
s_g->a[i][j]=sg[i][j];
if(s_0->a[i][j] == 0)
{
s_g->i_0=i;
s_g->j_0=j;
}
}
}
s_g->d=0;
s_g->w=w(s_g);
s_g->f=f(s_g);
OPEN->length=0;
CLOSED->length=0;
add_list(OPEN,s_0); //初始结点加入OPEN表中
printf("初始结点为:\n");
out_node(s_0);
printf("目标结点为:\n");
out_node(s_g);
}
上次更改时间:2012-12-31