启发式搜索解决8数码问题
来源:互联网 发布:linux telnet远程登录 编辑:程序博客网 时间:2024/05/21 19:38
启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直到目标。这样可以省略大量无谓的搜索路径,提高了效率。在启发式搜索中,对位置的估价是十分重要的。采用了不同的估价可以有不同的效果。
8数码中的启发式函数h(x)为节点x的格局与目标格局相比数码不同的位置个数
首先把初始节点S0放入open表中,然后每次从open表中取出未搜索过并且启发式函数值最小的节点进行扩展,直至到达目标状态,标记搜索过的状态我用的是康拓展开,即将相应的数字序列转化为一个整数
下面用C语言模拟8数码的搜索过程
输入起始状态和目标状态,用0表示空格
#include<stdio.h>#include<string.h>#include<math.h>#include<stdlib.h>#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<=ai<i) 例如3 5 7 4 1 2 9 6 8 展开为 X=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884*/int find(char str[9]) //用康拓展开将字符串转化为整数{int i,j,k;int sum=0;for(i=0;i<9;i++){k=0; //k记录当前数位的数大于后面的数的个数for(j=i+1;j<9;j++)if(str[i]>str[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<tail){if(open[head].num==0){printf("需要%d步到达目标状态\n状态变化变化依次如下\n",dis[find(open[head].z)]);print(find(open[head].z));return dis[find(open[head].z)];}for(i=0;i<9;i++)if(open[head].z[i]==0) //找到0所在的位置{x=i/3;y=i%3;zz=i;break;}for(i=0;i<4;i++){nx=x+dir[i][0];ny=y+dir[i][1];nz=nx*3+ny;if(0<=nx&&nx<3&&0<=ny&&ny<3){for(j=0;j<9;j++)open[tail].z[j]=open[head].z[j]; open[tail].z[zz]=open[head].z[nz];open[tail].z[nz]=0;open[tail].num=camp(open[tail].z,goal);t=find(open[tail].z);if(!visit[t]){visit[t]=1;dis[t]=dis[find(open[head].z)]+1;pre[t]=find(open[head].z);//记录上一个状态tail++;}}}head++;qsort(open+head,tail-1-head+1,sizeof(struct step),cmp);}printf("不可以到达\n");return -1;}int main(){freopen("output.txt", "w", stdout); int i;for(i=0;i<9;i++)scanf("%d",&open[0].z[i]);for(i=0;i<9;i++)scanf("%d",&goal[i]);bfs();fclose(stdout);return 0;}
- 启发式搜索解决8数码问题
- 八数码问题(启发式搜索)
- 【启发式搜索】八数码问题
- 启发式搜索-A*算法解决八数码问题
- 启发式搜索程序设计-八数码问题
- 八数码问题-启发式搜索(A*算法)
- 八数码问题: 八数码的游戏 九宫格里面放入8个数字 启发式搜索(1)
- 启发式搜索算法求解八数码问题(C)
- HDU 1043 Eight 八数码问题 A*搜索 启发式算法
- 八数码的启发式搜索
- 搜索训练1 [8数码问题]
- 八数码问题——双向广度优先搜索解决
- wikioi-天梯-提高一等-启发式搜索-1225:八数码难题
- HDU 1043 Eight poj 1077 (八数码 启发式搜索)
- 八数码游戏分析—启发式搜索算法(2)
- 八数码游戏(启发式搜索A*算法)
- 人工智能算法八数码之启发式搜索算法(A*)+扩展15数码算法的实现
- A*搜索 - 八数码问题
- virtualbox: Cannot register the hard disk
- HDOJ 4548 美素数
- “初识”三层架构
- C++纯虚函数详解
- rand和srand
- 启发式搜索解决8数码问题
- 我们要掌控什么——控制自己,就是控制未来
- Dx 1 error; aborting , Conversion to Dalvik format failed with error 1
- MFC--图片控件Picture Control
- 每日学习总结:"已有打开的与此命令相关联的 DataReader,必须首先将它关闭。"、Sql Server 连接池机制
- 服务程序性能优化之另辟蹊径
- JFreechart 制作柱状图、饼图、折线图、仪表图等统计图的使用方法
- 简单登录页面使用验证码
- HDOJ 4551 小明生日