启发式搜索解决8数码问题

启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径,提高了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。

8数码中的启发式函数h(x)为节点x的格局与目标格局相比数码不同的位置个数

首先把初始节点S0放入open表中,然后每次从open表中取出未搜索过并且启发式函数值最小的节点进行扩展,直至到达目标状态,标记搜索过的状态我用的是康拓展开,即将相应的数字序列转化为一个整数

下面用C语言模拟8数码的搜索过程

输入起始状态和目标状态,用0表示空格

#include
#include
#include
#include
#define N 363000 
struct step
{
	char z[9];
	int num; //当前节点的格局和目标节点格局相比数码不同的位置个数
}open[N];  //共有9!=362880种情况,用char存储节省空间
char goal[9];//目标状态 
char visit[N]; //标记该状态是否被访问
int dis[N]; //记录步长
int pre[N];//从上一步来的状态
int dir[4][2]={{1,0},{-1,0},{0,-1},{0,1}};   //搜索的4个方向
int c[9]={1,1,2,6,24,120,720,5040,40320};  //用于康拓展开
/* 
  康托展开: X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 
  ai为在当前未出现的数字中是排在第几个(0<=aistr[j])
		k++;
		sum+=k*c[8-i];
	}
	return sum;
}
void test(int x)  //逆康拓展开
{
	int res[9];
	int hash[9];
	int i,j,t,k;
	memset(hash,0,sizeof(hash));
	for(i=0;i<9;i++)
	{
		t=x/c[8-i];
		x-=t*c[8-i];
		k=0;
	    for(j=0;j<9;j++)
		{
			if(k==t&&!hash[j])
			{
				res[i]=j;
				hash[j]=1;
				break;
			}
			else if(!hash[j])
			{
				k++;
			}
		}
	}
    printf("%d%d%d\n",res[0],res[1],res[2]);
    printf("%d%d%d\n",res[3],res[4],res[5]);
	printf("%d%d%d\n",res[6],res[7],res[8]);
	printf("\n");
}
int camp(char str1[9],char str2[9])  //计算数码不同的位置个数
{
    int i,sum=0;
	for(i=0;i<9;i++)
	if(str1[i]!=str2[i])
	sum++;
	return sum;
}
int cmp(const void *a,const void *b)
{
	return (*(struct step *)a).num-(*(struct step *)b).num;
}
int print(int k)
{
	if(k==-1)
	{
	   return 0;
	}
	print(pre[k]);
	test(k);
	return 0;
}
int bfs()
{
	int i,j,t;
	int head,tail;
	int x,y,zz;
	int nx,ny,nz;
	memset(dis,0,sizeof(dis));  //到每种状态的步数
	memset(visit,0,sizeof(visit));  //标记过的状态不能重复走
	memset(pre,-1,sizeof(pre));
    t=find(open[0].z);
	visit[t]=1;
	open[0].num=camp(open[0].z,goal);
	head=0;
	tail=1;
	pre[t]=-1;
    while(head


启发式搜索解决8数码问题_第1张图片

你可能感兴趣的:(人工智能)