1.问题描述

在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。现在的问题是:对于指定的初始棋局和目标棋局,给出数码的移动序列。该问题称八数码难题或者重排九宫问题。

2.问题分析

八数码问题是个典型的状态图搜索问题。搜索方式有两种基本的方式,即树式搜索和线式搜索。搜索策略大体有盲目搜索和启发式搜索两大类。盲目搜索就是无“向导”的搜索,启发式搜索就是有“向导”的搜索。

启发式搜索:由于时间和空间资源的限制,穷举法只能解决一些状态空间很小的简单问题,而对于那些大状态空间的问题,穷举法就不能胜任,往往会导致“组合爆炸”。所以引入启发式搜索策略。启发式搜索就是利用启发性信息进行制导的搜索。它有利于快速找到问题的解。

由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零。所以,这个数码不同的位置个数便是标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息就可以指导搜索。即可以利用启发信息来扩展节点的选择,减少搜索范围,提高搜索速度。

启发函数设定。对于八数码问题,可以利用棋局差距作为一个度量。搜索过程中,差距会逐渐减少,最终为零,为零即搜索完成,得到目标棋局。

3.编制程序实现求解8数码问题算法,采用估价函数f(n)=d(n)+w(n)/p(n),

其中:d(n)是搜索树中结点的深度;w(n)为结点n的数据库中错放的棋子个数;p(n)为结点n的数据库中每个棋子与其目标位置之间的距离总和。分析两种估价函数求解8数码问题的效率差别,给出一个是p(n)的上界的h(n)的定义,并测试使用该估价函数是否使算法失去可采纳性。

4.算法思想

1) int goal[N][N],struct Chessboard:

定义goal数组为目标状态——{1,2,3,8,0,4,7,6,5}。结构体Chessboard记录棋盘信息,其中变量pos数组坐标记录每个数码a的位置,其值为数码a。d表示该棋盘的深度,f为启发函数值,move为父节点移动到该节点的方式,以便在输出时告诉用户该如何移动棋子知道目标状态。

2)struct LNode:

定义节点LNode结构体,存放该节点状态时的棋盘信息board,和指向父节点、下一节点的指针(*parent,*next),以及标记量flag——值为true时表示该节点是最佳路径上的节点。

3)int* Findzero(LNode* &Node):

为方便找到空格,设计找到该函数Findzero(*&Node),以便找到当前节点空格所在位置以利于接下来的程序执行。返回值为空格所在的行和列。

4)int Wrong(LNode *Node)和int pick(LNode *Node):分别为函数ω(n)和p(n)

5) LNode* extend(LNode *Node,int depth,int zero[2],int moveflag,int Choose)

树形方式扩展节点。Node为要扩展的当前节点,depth为当前深度,zero存放该节点空格位置信息,moveflag即扩展节点的移动方式,Choose为选择函数ω(n)还是p(n)

6)void InitList(LNode* &Open,LNode* &Close)和int ListInsert(List &L,LNode* NewNode)

分别为表OPEN、CLOSE的创建和表的插入操作。

7)LNode* Getminf(List &L)主要是实现从OPEN表中选择一个f值最小的节点i。如果有几个节点值相同,当其中

有一个为目标节点时,则选择此目标节点;否则就选择其中任一个节点作为节。

5.源代码

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define Overflow 1
#define N 3
int goal[N][N]={1,2,3,8,0,4,7,6,5};
int zero[2],NodeQTY=0;
int *z=zero;//记录0的位置,zero[0]:r行;zero[1]:c列
typedef int Piece;
struct Chessboard{//棋盘信息 Piece pos[N][N];//记录每个数码a的位置r行c列int d,f,move;//d:深度;f:启发函数值 ;move:父节点移动到该节点的方式
};
struct LNode{Chessboard board;LNode *parent,*next;bool flag;
};
typedef LNode* List;
int* Findzero(LNode* &Node)
{int i,j,zr[2];int *z=zr;for(i=0;i<N;i++){for(j=0;j<N;j++){if(Node->board.pos[i][j]==0){zr[0]=i+1;zr[1]=j+1;break;}}}return z;
}
int Wrong(LNode *Node)
{int w=0,i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(Node->board.pos[i][j]!=goal[i][j]&&Node->board.pos[i][j]!=0)w++;}}return w;
}
int pick(LNode *Node)
{int w=0,i,j,ii,jj;for(i=0;i<N;i++){for(j=0;j<N;j++){if(Node->board.pos[i][j]!=goal[i][j]&&Node->board.pos[i][j]!=0){for(ii=0;ii<N;ii++)for(jj=0;jj<N;jj++)if(Node->board.pos[i][j]==goal[ii][jj]){ w=w+abs(ii-i)+abs(jj-j);break; } }}}return w;
}
LNode* extend(LNode *Node,int depth,int zero[2],int moveflag,int Choose)
{LNode* NewNode=new LNode;for(int i=0;i<N;i++){for(int j=0;j<N;j++){NewNode->board.pos[i][j]=Node->board.pos[i][j];}}switch(moveflag){case 1:   //向左移,不能出界:zero[1]>=2NewNode->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]-1][zero[1]-2];NewNode->board.pos[zero[0]-1][zero[1]-2]=0;break;case 2:    //向右移,不能出界:zero[1]<=2NewNode->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]-1][zero[1]];NewNode->board.pos[zero[0]-1][zero[1]]=0;break;case 3:    //向上移,不能出界:zero[0]>=2NewNode->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]-2][zero[1]-1];NewNode->board.pos[zero[0]-2][zero[1]-1]=0;break;case 4:    //向下移,不能出界:zero[0]<=2NewNode->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]][zero[1]-1];NewNode->board.pos[zero[0]][zero[1]-1]=0;break;       }NewNode->board.d=depth+1;switch(Choose){case 1:NewNode->board.f=NewNode->board.d+Wrong(NewNode);break; case 2:NewNode->board.f=NewNode->board.d+pick(NewNode);break; } NewNode->board.move=moveflag;NewNode->parent=Node;NodeQTY++; return NewNode;
}
void InitList(LNode* &Open,LNode* &Close)
{Open=(List)malloc(sizeof(LNode));Close=(List)malloc(sizeof(LNode));if(!Open&&!Close)exit(Overflow);Open->next=NULL;Close->next=NULL;
}
int ListInsert(List &L,LNode* NewNode)
{List p=L;while(p->next){p=p->next;}NewNode->next=p->next;p->next=NewNode;return true;
}
LNode* Getminf(List &L)
{   List p=L,q=L->next,r=L,min;min=q;//p,q寻找f最小值的指针,r指向表L中min前一个元素 if(!q)return NULL;while(q){if(min->board.f>q->board.f){r=p;min=q;}p=q;q=q->next;}r->next=min->next;min->next=NULL;return min;
}int main()
{int i,j,choose;List Open,Close;LNode *Best,*current;LNode *Start=new LNode;printf("\t\t\t八 数 码 问 题 求 解\n"); printf("\n请输入初始状态:");for(i=0;i<N;i++){for(j=0;j<N;j++){scanf("%d",&(Start->board.pos[i][j]));}}printf("(注:The flag of movement--1:左移;2:右移;3:上移;4:下移)\n");printf("初始棋盘状态:\n"); for(i=0;i<N;i++){for(j=0;j<N;j++){printf("|%d",Start->board.pos[i][j]);}printf("|\n");}InitList(Open,Close);printf("请选择(1:A算法;2:A*算法):");scanf("%d",&choose); Start->board.d=0;switch(choose){case 1:Start->board.f=Start->board.d+Wrong(Start);break; case 2:Start->board.f=Start->board.d+pick(Start);break; } //   Start->board.f=0+Wrong(Start);Start->board.move=0;Start->parent=NULL;Start->next=NULL;Start->flag=1;ListInsert(Open,Start);//将S加入到Open表中 while(Open->next){Best=Getminf(Open);ListInsert(Close,Best);if(!(Best->board.f-Best->board.d)){printf("$$$******有解!******$$$\n"); break;}z=Findzero(Best);zero[0]=*(z+0);zero[1]=*(z+1);if(zero[1]>=N-1&&Best->board.move!=2) ListInsert(Open,extend(Best,Best->board.d,zero,1,choose));if(zero[1]<=N-1&&Best->board.move!=1)  ListInsert(Open,extend(Best,Best->board.d,zero,2,choose));if(zero[0]>=N-1&&Best->board.move!=4)  ListInsert(Open,extend(Best,Best->board.d,zero,3,choose));if(zero[0]<=N-1&&Best->board.move!=3)  ListInsert(Open,extend(Best,Best->board.d,zero,4,choose));}printf("本算法搜索图中总共扩展的节点数为:%d\n",NodeQTY); printf("\t最佳路径如下所示:\n"); if(Open->next){while(Best->parent){Best->flag=1;Best=Best->parent;}List p=Close->next,q=Close->next;if(p==Start) q=p->next;else   exit(1);int Step=0; while(p&&q)//在Close表中依标记找到路径 {if(q->flag==1&&q->parent==p){printf("Step %d:0 move as
the %d-flag of movement.\n",++Step,q->board.move);for(i=0;i<N;i++){for(j=0;j<N;j++){printf("|%d",q->board.pos[i][j]);}   printf("|\n");}p=q;//记住父节点 }q=q->next;   }printf("到达目标状态!\n"); }else    printf("该问题无法求解!\n");
}

启发式搜索解决八数码问题相关推荐

  1. Python利用A*算法解决八数码问题

    资源下载地址:https://download.csdn.net/download/sheziqiong/86790565 资源下载地址:https://download.csdn.net/downl ...

  2. Astar、A星算法解决八数码问题--python实现

    一.问题描述 数码问题又称9宫问题,与游戏"华容道"类似.意在给定的3*3棋格的8个格子内分别放一个符号,符号之间互不相同,余下的一格为空格.并且通常把8个符号在棋格上的排列顺序称 ...

  3. A*算法解决八数码问题 Java语言实现

    A*算法解决八数码问题 Java语言实现 参考文章: (1)A*算法解决八数码问题 Java语言实现 (2)https://www.cnblogs.com/beilin/p/5981483.html ...

  4. 题目2:隐式图的搜索问题(A*算法解决八数码)

    数据结构课程实践系列 题目1:学生成绩档案管理系统(实验准备) 题目2:隐式图的搜索问题(A*算法解决八数码) 题目3:文本文件单词的检索与计数(实验准备) 文章目录 数据结构课程实践系列 题目1:学 ...

  5. python---A*搜索算法解决八数码问题

    A*解决八数码问题 问题内容 算法流程 相关设置 具体程序 运行结果 遇到的问题 完结 问题内容 [八数码问题] 在一个3×3的九宫中有1-8这8个数字以及一个空格随机摆放在其中的格子里.将该九宫格调 ...

  6. 宽度优先搜索算法解决八数码问题

    宽度优先搜索算法解决八数码问题 原理 1.宽度优先搜索是指在一个搜索树中,搜索以同层邻近节点依次扩展节点.这种搜索是逐层进行的,在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点. 宽度优先搜 ...

  7. Nilsson's sequence score算法解决八数码问题解释

    解决了最近一个人工智能关于解决八数码难题的作业. 图可能看不清,除了黑块外其他位置是英文字母ABCDEFGH A*:f(n)=g(n)+h(n) 其中f为总花费,g为已知花费(深度),h为估计花费 关 ...

  8. 深度优先搜索解决八数码难题

    八数码问题 以前用java写的通过深度优先瘦素解决八数码难题. 对于八数码难题来说,可以把9宫格看成一个[3][3]的二维数组,将空格位置看成0,将0可以移动的方向看成树的枝丫,分为上下左右4个方向. ...

  9. A*算法解决八数码问题 人工智能原理实验报告 启发式搜索 python

    目录 一.实验主要步骤 ①.设计界面输入规则 ②.判断是否有解 ③.求解 二.实验结果展示 三.附录 完整实验程序代码: 一.实验主要步骤 ①.设计界面输入规则 有且仅有9位数字代表数码和空格,从左到 ...

  10. 全局择优搜索、A*算法、宽度优先算法解决八数码问题

    1问题描述 使用盲目搜索中的宽度优先搜索算法或者使用启发式搜索中的全局择优搜索或A算法,对任意的八数码问题给出求解结果.例如:对于如下具体的八数码问题: 通过设计启发函数,编程实现求解过程,如果问题有 ...

最新文章

  1. jQuery UI vs Kendo UI jQuery Mobile vs Kendo UI Mobile
  2. 【SICP练习】38 练习1.43
  3. QT STUDY 模型-视图-控制器
  4. zabbix mysql模板_zabbix模板监控mysql
  5. 发送请求获取响应内容(c#)
  6. Java自动装箱后的值比较
  7. kaggle的图像数据集直接下载到google drive
  8. 【聊一聊】css中的经典布局——圣杯布局
  9. python多继承_Python多继承,__init__
  10. 转贴:Icon Design Guidelines, Android 2.0
  11. 8086cpu学习笔记(3):寻址方式
  12. Oracle 10g RMAN 跨平台迁移
  13. jQuery倒计时插件
  14. python计算几周零几天_Python自定义函数计算给定日期是该年第几天的方法示例
  15. 将年月日成一年中第几天
  16. php公众号提现功能,公众号赞赏提现
  17. c语言int 转bool_深入理解C语言中的类型转换
  18. es6转es5 的6种方式
  19. monkey稳定性测试
  20. struts使用下拉列表框

热门文章

  1. sklearn 手写体识别
  2. 海思 Hi3559A Sample_vdec视频解码及编译
  3. ARINC485和RS485的区别
  4. kali系统更新命令
  5. ACI注册国际项目考试地点汇总
  6. 高一计算机组装与维护教学总结,计算机优秀个人教学总结
  7. fixdown down,一个时代的终结。
  8. 马成荣版计算机应用基础 教案,计算机基础教案.doc
  9. 软件设计师真题知识点笔记❀
  10. 单片机简单的计算器c语言程序,AT89S52单片机实现简易计算器(C语言程序)