“八数码问题求解”程序说明
启发式搜索解决八数码问题
![启发式搜索解决八数码问题](https://img.taocdn.com/s3/m/0286148884868762caaed5fa.png)
#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;elseb[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 步即可完成。
人工智能8位数码难题的问题求解
![人工智能8位数码难题的问题求解](https://img.taocdn.com/s3/m/e4f7d722c5da50e2524d7fdb.png)
#define DOWN 1
#define LEFT 2
#define RIGHT 3
#define Bit char
typedef struct maps
{
Bit detail[9];
int myindex; //记录自己节点在hash表中的位置
Bit position; //记录空格(0)在序列中的位置
实验软硬件要求:网络计算机,c++编程环境
实验内容、方法和步骤(可附页)
我们将八数码难题分布在3×3方格棋盘上,分别放置了标有数字1,2,3,4,5,6,7,8的八张牌,初始状态S0,目标状态如图所示,可以使用的操作有:空格上移,空格左移,空格右移,空格下移。我们将是用广度优先搜索算法来解决这一问题。
int newindex = Parent.myindex ;
Bit *p = Parent.detail;
switch(direct)
{
case UP :
{
newindex -= 3*40320 ;
newindex += ( p[ i - 2 ] > p[ i - 3 ]) ? ( Factorial[ p[ i - 3 ] ] ) : ( - Factorial[ p[ i - 2 ] ] );
}p,*PMap;
Map org; //初始状态
int EndIndex; //目标,上移,下移,左移,右移
int const derection[4] ={ -3 , 3 , -1 , 1 } ;
//可移动的四个方向
int const Factorial[9] = {40320 , 5040 , 720 , 120 , 24 , 6 , 2 , 1 , 1 };
a星算法求解八数码问题python
![a星算法求解八数码问题python](https://img.taocdn.com/s3/m/987dbde548649b6648d7c1c708a1284ac950057c.png)
a星算法求解八数码问题python一、介绍八数码问题是一种经典的智力游戏,也是人工智能领域中的经典问题之一。
在这个问题中,有一个3×3的棋盘,上面摆着1至8这8个数字和一个空格,初始状态和目标状态都已知。
要求通过移动数字,将初始状态变换成目标状态。
其中空格可以和相邻的数字交换位置。
为了解决这个问题,我们可以使用A*算法。
本文将详细介绍如何用Python实现A*算法来求解八数码问题。
二、A*算法简介A*算法是一种启发式搜索算法,常用于寻找最短路径或最优解等问题。
它基于Dijkstra算法,并加入了启发式函数来加速搜索过程。
在A*算法中,每个节点都有两个估价值:g值和h值。
g值表示从起点到该节点的实际代价,h值表示从该节点到目标节点的估计代价。
启发式函数f(n) = g(n) + h(n) 表示从起点到目标节点的估计总代价。
A*算法采用优先队列来保存待扩展的节点,并按照f(n)值从小到大排序。
每次取出队头元素进行扩展,并将扩展出来的新节点按照f(n)值插入队列中。
当扩展出目标节点时,算法结束。
三、八数码问题的状态表示在八数码问题中,每个状态都可以表示为一个3×3的矩阵。
我们可以用一个一维数组来表示这个矩阵,其中0表示空格。
例如,初始状态可以表示为[2, 8, 3, 1, 6, 4, 7, 0, 5],目标状态可以表示为[1, 2, 3, 8, 0, 4, 7, 6, 5]。
四、A*算法求解八数码问题的步骤1.将初始状态加入优先队列中,并设置g值和h值为0。
2.从队头取出一个节点进行扩展。
如果该节点是目标节点,则搜索结束;否则,将扩展出来的新节点加入优先队列中。
3.对于每个新节点,计算g值和h值,并更新f(n)值。
如果该节点已经在优先队列中,则更新其估价值;否则,将其加入优先队列中。
4.重复第2步至第3步直到搜索结束。
五、Python实现以下是用Python实现A*算法求解八数码问题的代码:```import heapqimport copy# 目标状态goal_state = [1,2,3,8,0,4,7,6,5]# 启发式函数:曼哈顿距离def h(state):distance = 0for i in range(9):if state[i] == 0:continuerow = i // 3col = i % 3goal_row = (state[i]-1) // 3goal_col = (state[i]-1) % 3distance += abs(row - goal_row) + abs(col - goal_col)return distance# A*算法def A_star(start_state):# 初始化优先队列和已访问集合queue = []visited = set()# 将初始状态加入优先队列中,并设置g值和h值为0heapq.heappush(queue, (h(start_state), start_state, 0))while queue:# 取出队头元素进行扩展f, state, g = heapq.heappop(queue)# 如果该节点是目标节点,则搜索结束;否则,将扩展出来的新节点加入优先队列中。
8数码问题分析及程序代码
![8数码问题分析及程序代码](https://img.taocdn.com/s3/m/f4ca8fed172ded630b1cb616.png)
八数码问题1、问题描述所谓八数码问题是指:将分别标有数字1,2,3,…,8的八块正方形数码牌任意地放在一块3×3的数码盘上。
放牌时要求不能重叠。
于是,在3×3的数码盘上出现了一个空格。
现在要求按照每次只能将与空格相邻的数码牌与空格交换的原则,将任意摆放的数码盘逐步摆成某种特殊的排列。
2、问题分析首先,八数码问题包括一个初始状态(strat) 和 目标状态(goal),所谓解八数码问题就是在两个状态间寻找一系列可过渡状态(strat-> strat 1-> strat 2->...->goal )。
这个状态是否存在表示空格)图13、 数据结构 定义结构体Node 如下: typedef struct{int num[9];char cur_expension; //记录是否可以扩展,Y 代表可以扩展,N 代表不可以。
char Operate; //表示不可以执行的操作,'L'代表不能左移,'R'代表不能右移, //'U'代表不能上移,'D'代表不能下移,'C'代表可以任意移动。
int father; //记录父节点的下标。
}Node;Node state[MAXSIZE]; //将搜索过的状态存储于该数组中。
4、广度优先搜索广度优先搜索是指按节点的层次进行搜索,本层的节点没有搜索完毕时,不能对下层节点进行处理,即深度越小的节点越先得到扩展,也就是说先产生的节点先得以扩展处理,直至找到目标为止。
求解八数码问题的搜索过程:如图2所示,把所有可能的算符应用到开始节点(即空格上移、空格左移、空格右移、空格下移),图2只是演示了两个扩展结点,如此继续下去,直到发现目标节点。
图2 变量定义及函数说明:1 2 3 45 6 7 8 01 2 37 4 5 8 0 61 2 34 5 67 8 0#define SUM 100//限定只搜索前50步,50步以后如果仍然没有搜索到结果,认为无解。
西电八数码问题求解
![西电八数码问题求解](https://img.taocdn.com/s3/m/1003651f14791711cc79171f.png)
西安电子科技大学课程论文数据结构八数码问题的求解班级:作者:学号:时间:摘要八数码问题也称为九宫问题,在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。
棋盘上还有一个空格(以0标记),与空格相邻的棋子可以移到空格中。
给定初始位置和目标位置,要求通过一系列的数码移动,将初始状态转化为目标状态。
状态转换的规则:空格四周的数移向空格,我们可以看作是空格移动,它最多可以有4个方向的移动,即上、下、左、右。
九宫重排问题的求解方法,就是从给定的初始状态出发,不断地空格上下左右的数码移至空格,将一个状态转化成其它状态,直到产生目标状态。
一般用搜索法来解决:广度优先搜索法、深度优先搜索法、A*算法等,本文用全局择优来解决该问题。
引言八数码问题是人工智能中一个很典型的智力问题。
一般用搜索法来解决:广度优先搜索法、深度优先搜索法、A*算法等。
搜索就是按照一定规则扩展已知结点,直到找到目标结点或所有结点都不能扩展为止,广度优先是从初始状态一层一层向下找,直到找到目标为止。
深度优先是按照一定的顺序前查找完一个分支,再查找另一个分支,以至找到目标为止。
广度和深度优先搜索有一个很大的缺陷就是他们都是在一个给定的状态空间中穷举。
由于八数码问题状态空间共有9!个状态,对于八数码问题如果选定了初始状态和目标状态,有9!/2个状态要搜索,考虑到时间和空间的限制,在这里采用A*算法作为搜索策略。
A*是一种静态路网中求解最短路径最有效的方法,公式表示为:f(n)=g(n)+h(n),其中f(n) 是从初始点经由节点n到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n) 是从n到目标节点最佳路径的估计代价,保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取。
一、需求分析①八数码游戏(八数码问题)描述为:在3×3组成的九宫格棋盘上,摆有八个将牌,每一个将牌都刻有1-8八个数码中的某一个数码。
用A算法解决八数码问题
![用A算法解决八数码问题](https://img.taocdn.com/s3/m/893a91a584254b35eefd34ac.png)
用A*算法解决八数码问题一、 题目:八数码问题也称为九宫问题。
在3×3的棋盘,有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。
棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。
要解决的问题是:任意给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
二、 问题的搜索形式描述状态:状态描述了8个棋子和空位在棋盘的9个方格上的分布。
初始状态:任何状态都可以被指定为初始状态。
操作符:用来产生4个行动(上下左右移动)。
目标测试:用来检测状态是否能匹配上图的目标布局。
路径费用函数:每一步的费用为1,因此整个路径的费用是路径中的步数。
现在任意给定一个初始状态,要求找到一种搜索策略,用尽可能少的步数得到上图的目标状态算法介绍三、 解决方案介绍1.A*算法的一般介绍A*(A-Star)算法是一种静态路网中求解最短路最有效的方法。
对于几何路网来说,可以取两节点间欧几理德距离(直线距离)做为估价值,即()()()()()()**f g n sqrt dx nx dx nx dy ny dy ny =+--+--;这样估价函数f 在g 值一定的情况下,会或多或少的受估价值h 的制约,节点距目标点近,h 值小,f 值相对就小,能保证最短路的搜索向终点的方向进行。
明显优于盲目搜索策略。
A star算法在静态路网中的应用2.算法伪代码创建两个表,OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点。
算起点的估价值,将起点放入OPEN表。
while(OPEN!=NULL){从OPEN表中取估价值f最小的节点n;if(n节点==目标节点){break;}for(当前节点n 的每个子节点X){算X的估价值;if(X in OPEN){if( X的估价值小于OPEN表的估价值 ){把n设置为X的父亲;更新OPEN表中的估价值; //取最小路径的估价值}}if(X inCLOSE){if( X的估价值小于CLOSE表的估价值 ){把n设置为X的父亲;更新CLOSE表中的估价值;把X节点放入OPEN //取最小路径的估价值}}if(X not inboth){把n设置为X的父亲;求X的估价值;并将X插入OPEN表中; //还没有排序}}//end for将n节点插入CLOSE表中;按照估价值将OPEN表中的节点排序; //实际上是比较OPEN表内节点f的大小,从最小路径的节点向下进行。
A-star-算法-八数码问题-C++-报告+代码+详细注释1
![A-star-算法-八数码问题-C++-报告+代码+详细注释1](https://img.taocdn.com/s3/m/08af3a211611cc7931b765ce0508763230127440.png)
二、程序运行测试A*算法求解八数码问题一、详细设计说明1.评价函数以当前状态下各将牌到目标位置的距离之和作为节点的评价标准。
距离的定义为: “某将牌行下标与目标位置行下标之差的绝对值 + 列下标与目标位置列下标之差的绝对值”。
距离越小, 该节点的效果越好。
某个状态所有将牌到目标位置的距离之和用“h值”表示。
2.主要函数2.1countH(state & st);countH函数功能是计算st状态的h值。
2.2计算过程中将会用到rightPos数组, 数组里记录的是目标状态下, 0~9每个将牌在九宫格里的位置(位置 = 行下标 * 3 + 列下标)。
2.3f(state * p);f()=h()+level2.4look_up_dup(vector<state*> & vec, state * p);2.5在open表或close表中, 是否存在指定状态p, 当找到与p完全相等的节点时, 退出函数。
2.6search(state & start);在open表不为空时, 按f值由小到大对open表中元素进行排序。
调用findZero()函数找到0值元素的位置。
空格可以向上下左右四个方向移动, 前提是移动后不能越过九宫格的边界线。
确定某方向可走后, 空格移动一步, 生成状态p’。
2.7此时, 检查open表中是否已有p’, 若有, 更新p’数据;检查close表中是否已有p’, 若有, 将p’从close表中删除, 添加到open表中。
2.8重复的执行这个过程, 直到某状态的h值为零。
2.9dump_solution(state * q);在终端输出解路径。
// A*算法八数码问题#include"stdafx.h"#include<iostream>#include<vector>#include<time.h>#include<algorithm>using namespace std;const int GRID = 3; //Grid表示表格的行数(列数), 这是3*3的九宫格int rightPos[9] = { 4, 0, 1, 2, 5, 8, 7, 6, 3 };//目标状态时, 若p[i][j]=OMG,那么3*i+j = rightPos[OMG]struct state{int panel[GRID][GRID];int level; //记录深度int h;state * parent;state(int level) :level(level){}bool operator == (state & q){//判断两个状态是否完全相等(对应位置元素相等), 完全相等返回true,否则返回falsefor (int i = 0; i<GRID; i++){for (int j = 0; j<GRID; j++){if (panel[i][j] != q.panel[i][j])return false;}}return true;}state & operator = (state & p){ //以状态p为当前状态赋值, 对应位置元素相同for (int i = 0; i<GRID; i++){for (int j = 0; j<GRID; j++){panel[i][j] = p.panel[i][j];}}return *this;}};void dump_panel(state * p){ //将八数码按3*3矩阵形式输出for (int i = 0; i<GRID; i++){for (int j = 0; j<GRID; j++)cout << p->panel[i][j] << " ";cout << endl;}}int countH(state & st){ //给定状态st, 计算它的h值。
八数码难题
![八数码难题](https://img.taocdn.com/s3/m/5a9724c3d5bbfd0a79567357.png)
已解决八数码难题悬赏分:200 - 解决时间:2005-10-10 19:41问题描述:有一个3*3的棋盘,其中有0-8 9个数字,0表示空格,其他的数字可以和0交换位置。
求由初始状态1 2 34 5 67 8 0到达目标状态步数最少的解。
问题补充:最好用c提问者:华雯- 见习魔法师三级最佳答案输入方法:例如:input(从键盘):1 2 3 7 4 5 8 0 6output(向屏幕):Step:11 2 34 5 67 8 0Step:21 2 34 5 07 8 6Step:31 2 34 0 57 8 6Step:41 2 30 4 57 8 6Step:51 2 37 4 50 8 6Step:67 4 58 0 6我的程序:#include <stdio.h>#include <math.h>#include <CONIO.h>struct bsm{int s[9];int prep,pos;} ar1[1000],ar2[1000];int h1,r1,h2,r2,step;struct bsm p;int pd(int k){int i,j,b1,b2;b1=1;p.s[p.pos+k]=p.s[p.pos]+p.s[p.pos+k]; p.s[p.pos]=p.s[p.pos+k]-p.s[p.pos]; p.s[p.pos+k]=p.s[p.pos+k]-p.s[p.pos]; p.pos=p.pos+k;for (i=0;i<=r1;i++){b2=0;for (j=0;j<9;j++)if (!(ar1[i].s[j]==p.s[j])) b2=1;b1=b1*b2;}return(b1);}int pd0(int k){int i,j,b1,b2;b1=1;p.s[p.pos+k]=p.s[p.pos]+p.s[p.pos+k]; p.s[p.pos]=p.s[p.pos+k]-p.s[p.pos]; p.s[p.pos+k]=p.s[p.pos+k]-p.s[p.pos]; p.pos=p.pos+k;for (i=0;i<=r2;i++){for (j=0;j<9;j++)if (!(ar2[i].s[j]==p.s[j])) b2=1; b1=b1*b2;}return(b1);}int pd1(){int i,j,b1,b2;b1=0;for (i=h2;i<=r2;i++){b2=0;for (j=0;j<9;j++)if (!(ar2[i].s[j]==p.s[j])) b2=1; if (0==b2){r2=i;b1=1;}}return(b1);}int pd2(){int i,j,b1,b2;b1=0;for (i=h1;i<=r1;i++){b2=0;for (j=0;j<9;j++)if (!(ar1[i].s[j]==p.s[j])) b2=1; if (0==b2){r1=i;b1=1;}}return(b1);}void out1(struct bsm m) {int i,j;step++;printf("Step:%d",step); for (i=0;i<9;i++){if (0==i%3) printf("\n"); printf("%d ",m.s[i]);}while (!kbhit());i=getch();printf("\n");}void out(){int i,j,k;int arr[1000];j=-1;while (r1>0){j=j+1;arr[j]=r1;r1=ar1[r1].prep;}j=j+1;arr[j]=r1;for (i=j;i>-1;i--){out1(ar1[arr[i]]);}while (r2>0){out1(ar2[ar2[r2].prep]); r2=ar2[r2].prep;}}void main(){int i,j;step=0;for (i=0;i<9;i++){ar1[0].s[i]=(i+1)%9;scanf("%d",&ar2[0].s[i]);if (0==ar2[0].s[i]) ar2[0].pos=i;}ar1[0].pos=8;ar1[0].prep=-1;ar2[0].prep=-1;h1=0;r1=0;h2=0;r2=0;while(((h1<=r1)&&(r1<999))||((h2<=r2)&&(r2<999))) {if ((h1<=r1)&&(r1<999)){p=ar1[h1];if (p.pos>2){if (1==pd(-3)){p.prep=h1;r1++;ar1[r1]=p;if (1==pd1()){out();return;}}}p=ar1[h1];if (p.pos%3>0){if (1==pd(-1)){p.prep=h1;r1++;ar1[r1]=p;if (1==pd1()){out();return;}}}p=ar1[h1];if (p.pos<6){if (1==pd(3)){p.prep=h1;r1++;ar1[r1]=p;if (1==pd1()){out();return;}}}p=ar1[h1];if (p.pos%3<2){if (1==pd(1)){p.prep=h1;r1++;ar1[r1]=p;if (1==pd1()){out();return;}}}h1++;}if ((h2<=r2)&&(r2<999)) {p=ar2[h2];if (p.pos>2){if (1==pd0(-3)){p.prep=h2;r2++;ar2[r2]=p;if (1==pd2()) {out();return;}}}p=ar2[h2];if (p.pos%3>0) {if (1==pd0(-1)) {p.prep=h2;r2++;ar2[r2]=p;if (1==pd2()) {out();return;}}}p=ar2[h2];if (p.pos<6) {if (1==pd0(3)) {p.prep=h2;r2++;ar2[r2]=p;if (1==pd2()) {out();return;}}}p=ar2[h2];if (p.pos%3<2) {if (1==pd0(1)) {p.prep=h2;r2++;ar2[r2]=p;if (1==pd2()){out();return;}}}h2++;}}if (step==0) printf("I cannot find the answer!");}回答者:阿宁_9527 -试用期一级10-10 13:23提问者对于答案的评价:不是很好,将就着用吧。
人工智能实验八数码问题的求解策略
![人工智能实验八数码问题的求解策略](https://img.taocdn.com/s3/m/11256c049ec3d5bbfd0a74e6.png)
(declare (special *open*))
(declare (special *closed*))
(let (child rest tuple)
(cond ((null moves) nil)
(t (setq child (funcall (car moves) state))
(set-state-value new-state blank-row blank-col left-value)
(set-state-value new-state blank-row (- blank-col 1) '*)
(set-blank-col new-state (- blank-col 1))
(setq new-state (copy-tree state))
(setq blank-row (get-blank-row state))
(setq blank-col (get-blank-col state))
(cond ((> blank-col 0)
(setq left-value (get-state-value new-state blank-row (- blank-col 1)))
(t
(setq tuple (car *open*) )
(setq state (car tuple) )
(setq *open* (cdr *open*) )
(setq *closed* (cons tuple *closed*))
(cond ((equal state *goal*)
(setq path (get-path-from *goal*))
八数码(双向搜索)解题报告
![八数码(双向搜索)解题报告](https://img.taocdn.com/s3/m/7f023980d4d8d15abe234e04.png)
a)广搜的优化:用布尔数组、哈希表、二叉排序树等提高判重效率,用双向搜索、滚动数组改善空间效率,用二进制改进产生式、存储空间以及判重效率例题:【问题描述】:在3 * 3 的棋盘上,摆有八个棋子,每个棋子上标有1 至8 的某一数字。
棋盘中留有一个空格。
空格周围的棋子可以移到空格中。
要求解的问题是,给出一种初始布局[ 初始状态] 和目标布局[ 目标状态] ,输出从初始布局到目标布局的转变至少需要的步数。
【输入格式】输入由两行组成,每行8个数,分别表示初始状态和目标状态:【输出格式】输出步数,若无解输出“No solution!”。
【输入输出样例】输入文件名:8num.in283164705123804765输出文件名:8num.out5时限:前两组数据不超过1秒,第三组数据不超过10秒program shuangguang8; {Made By P.D.B (AYLA)}{此程序可全部AC,用时0 ms}const ji:array[1..8]of longint=(40320,5040,720,120,24,6,2,1);{康托展开时用到的常数,分别为为9-1的阶乘}var d1,d2:array[0..10000]of string[10];{两个队,分别存放双向广搜的一支} k1,k2:array[0..370000]of boolean;{Hash表,康托展开的数组,判重用}kb1,kb2:array[0..370000]of integer;{Hash表,康托展开的数组,存放每种情况的步数}fu1,fu2:array[0..10000]of integer;{两个队,存放当前步数}w1,w2,h1,t1,h2,t2,i,j,tol,lei,b:longint;m,n,z:string[10];l,c:char;{辅助变量} procedure print;{输出}beginwriteln(kb1[lei]+kb2[lei]);{从起始到当前情况与从目标到当前情况的步数和} halt;end;function PDhash1(x:string):boolean;{判断当前情况在队列1中是否重复}beginlei:=0;for i:=8 downto 1 do {康托展开,i表示当前位数}begintol:=0;for j:=i to 9 do {将当前位数前比当前位数大的数的个数与当前位数的阶乘相乘,并累加到l变量lei中}if x[i]>x[j] then inc(tol);lei:=lei+ji[i]*tol;end;PDhash1:=k1[lei];end;function PDhash2(x:string):boolean;{判断当前情况在队列2中是否重复}beginlei:=0;for i:=8 downto 1 dobegintol:=0;for j:=i to 9 doif x[i]>x[j] then inc(tol);lei:=lei+ji[i]*tol;end;PDhash2:=k2[lei];end;procedure hash1(x:string[10]);{将当前情况加入到队列1的Hash表中,可与PDhash1过程合并,为便于理解将其分开}beginlei:=0;for i:=8 downto 1 dobegintol:=0;for j:=i to 9 doif x[i]>x[j] then inc(tol);lei:=lei+ji[i]*tol;end;k1[lei]:=true;kb1[lei]:=fu1[t1]; {将当前步数存入康托展开后的数组中}if k2[lei] then print; {如果反向搜索状态中由此情况,则输出,并结束程序} end;procedure hash2(x:string[10]);{将当前情况加入到队列2的Hash表中,可与PDhash2过程合并,为便于理解将其分开}beginlei:=0;for i:=8 downto 1 dobegintol:=0;for j:=i to 9 doif x[i]>x[j] then inc(tol);lei:=lei+ji[i]*tol;end;k2[lei]:=true;kb2[lei]:=fu2[t2]; {将当前步数存入康托展开后的数组中}if k1[lei] then print; {如果正向搜索状态中由此情况,则输出,并结束程序} end;procedure init;{读入}beginfillchar(k1,sizeof(k1),false);fillchar(k2,sizeof(k2),false);{for i:=1 to 3 dobeginfor j:=1 to 3 dobeginread(c); m:=m+c; read(c);end;readln;end;}m:='123456780';for i:=1 to 3 dobeginfor j:=1 to 3 dobeginread(c); n:=n+c; read(c);end;readln;end;end;procedure WFS;{双向广搜}begint1:=1;t2:=1;h1:=0;h2:=0;repeatinc(h1); {正向搜索}w1:=pos('0',d1[h1]);if w1-3>0 then {查找'0'的位置,判断'0'可移动的方向}beginz:=d1[h1];l:=z[w1];z[w1]:=z[w1-3];z[w1-3]:=l;{移动'0'}if not PDhash1(z) then {判断是否重复}begininc(t1); d1[t1]:=z;fu1[t1]:=fu1[h1]+1; {当前情况步数等于其父节点的步数加1}hash1(z); {加入Hash表}end;end;if w1+3<10 thenbeginz:=d1[h1];l:=z[w1];z[w1]:=z[w1+3];z[w1+3]:=l;if not PDhash1(z) thenbegininc(t1); d1[t1]:=z;fu1[t1]:=fu1[h1]+1;hash1(z);end;end;case w1 mod 3 of {判断'0'可移动的方向}0: beginz:=d1[h1];l:=z[w1];z[w1]:=z[w1-1];z[w1-1]:=l;if not PDhash1(z) thenbegininc(t1); d1[t1]:=z;fu1[t1]:=fu1[h1]+1;hash1(z);end;end;1: beginz:=d1[h1];l:=z[w1];z[w1]:=z[w1+1];z[w1+1]:=l;if not PDhash1(z) thenbegininc(t1); d1[t1]:=z;fu1[t1]:=fu1[h1]+1;hash1(z);end;end;2:beginz:=d1[h1];l:=z[w1];z[w1]:=z[w1-1];z[w1-1]:=l;if not PDhash1(z) thenbegininc(t1); d1[t1]:=z;fu1[t1]:=fu1[h1]+1;hash1(z);end;z:=d1[h1];l:=z[w1];z[w1]:=z[w1+1];z[w1+1]:=l;if not PDhash1(z) thenbegininc(t1);d1[t1]:=z;fu1[t1]:=fu1[h1]+1;hash1(z);end;end;end;inc(h2);{反向搜索,过程与正向搜索基本相同}w1:=pos('0',d2[h2]);if w1-3>0 thenbeginz:=d2[h2];l:=z[w1];z[w1]:=z[w1-3];z[w1-3]:=l;if not PDhash2(z) thenbegininc(t2);d2[t2]:=z;fu2[t2]:=fu2[h2]+1;hash2(z);end;end;if w1+3<10 thenbeginz:=d2[h2];l:=z[w1];z[w1]:=z[w1+3];z[w1+3]:=l;if not PDhash2(z) thenbegininc(t2);d2[t2]:=z;fu2[t2]:=fu2[h2]+1;hash2(z);end;end;case w1 mod 3 of0: beginz:=d2[h2];l:=z[w1];z[w1]:=z[w1-1];z[w1-1]:=l;if not PDhash2(z) thenbegininc(t2);d2[t2]:=z;fu2[t2]:=fu2[h2]+1;hash2(z);end;end;1: beginz:=d2[h2];l:=z[w1];z[w1]:=z[w1+1];z[w1+1]:=l;if not PDhash2(z) thenbegininc(t2); d2[t2]:=z;fu2[t2]:=fu2[h2]+1;hash2(z);end;end;2:beginz:=d2[h2];l:=z[w1];z[w1]:=z[w1-1];z[w1-1]:=l;if not PDhash2(z) thenbegininc(t2); d2[t2]:=z;fu2[t2]:=fu2[h2]+1;hash2(z);end;z:=d2[h2];l:=z[w1];z[w1]:=z[w1+1];z[w1+1]:=l;if not PDhash2(z) thenbegininc(t2); d2[t2]:=z;fu2[t2]:=fu2[h2]+1;hash2(z);end;end;end;until (h2>=t2)or(h1>=t1);end;begin {主程序,十分简洁}init;d1[1]:=m; {初始化,队中存入起始状态}d2[1]:=n; {初始化,队中存入目标状态}hash1(m);hash2(n);WFS;writeln('Impossible'); {无解则输出Impossible} end.。
人工智能实验报告 八数码问题
![人工智能实验报告 八数码问题](https://img.taocdn.com/s3/m/daa2390b844769eae009ed7c.png)
实验一 启发式搜索算法姓名:徐维坚 学号:2220103484 日期:2012/6/29一、实验目的:熟练掌握启发式搜索A *算法及其可采纳性。
二、实验内容:使用启发式搜索算法求解8数码问题。
1) 编制程序实现求解8数码问题A *算法,采用估价函数()()()()w n f n d n p n ⎧⎪=+⎨⎪⎩, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。
2) 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界 的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。
三、实验原理:1. 问题描述:八数码问题也称为九宫问题。
在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。
棋盘上还有一个空格(以数字0来表示),与空格相邻的棋子可以移到空格中。
要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
所谓问题的一个状态就是棋子在棋盘上的一种摆法。
解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。
2. 原理描述:2.1 有序搜索算法:(1)原理:在搜索过程中,OPEN 表中节点按照其估价函数值以递增顺序排列,选择OPEN 表中具有最小估价函数值的节点作为下一个待扩展的节点,这种搜索方法称为有序搜索。
在本例中,估价函数中的)(n g 取节点深度)(n d ,)(n h 为节点n 的状态与目标状态之间错放的个数,即函数)(n ω。
(2)算法描述:① 把起始节点S 放到OPEN 表中,并计算节点S 的)(S f ;② 如果OPEN 是空表,则失败退出,无解;③ 从OPEN 表中选择一个f 值最小的节点i 。
如果有几个节点值相同,当其中有一个 为目标节点时,则选择此目标节点;否则就选择其中任一个节点作为节点i ;④ 把节点i 从 OPEN 表中移出,并把它放入 CLOSED 的已扩展节点表中;⑤ 如果i 是个目标节点,则成功退出,求得一个解;⑥ 扩展节点i ,生成其全部后继节点。
八数码问题求解--实验报告讲解
![八数码问题求解--实验报告讲解](https://img.taocdn.com/s3/m/053482ddba1aa8114531d9b6.png)
实验报告一、实验问题八数码问题求解二、实验软件VC6.0 编程语言或其它编程语言三、实验目的1. 熟悉人工智能系统中的问题求解过程;2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用;3. 熟悉对八数码问题的建模、求解及编程语言的应用。
四、实验数据及步骤(一、)实验内容八数码问题:在3 ×3 的方格棋盘上,摆放着1 到8 这八个数码,有1 个方格是空的,其初始状态如图1 所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
2 83 1 2 31 4 8 47 6 5 7 6 5(a) 初始状态(b) 目标状态图1 八数码问题示意图(二、)基本数据结构分析和实现1. 结点状态我采用了struct Node 数据类型typedef struct _Node{int digit[ROW][COL];int dist; // distance between one state and the destination 个表和目的表的距离int dep; // the depth of node 深度// So the comment function = dist + dep. 估价函数值int index; // point to the location of parent 父节点的位置} Node; 2. 发生器函数定义的发生器函数由以下的四种操作组成:(1) 将当前状态的空格上移Node node_up;Assign(node_up, index);// 向上扩展的节点int dist_up = MAXDISTANCE;(2) 将当前状态的空格下移Node node_down;Assign(node_down, index);// 向下扩展的节点int dist_down = MAXDISTANCE;(3) 将当前状态的空格左移Node node_left;Assign(node_left, index);// 向左扩展的节点int dist_left = MAXDISTANCE;(4) 将当前状态的空格右移Node node_right;Assign(node_right, index);// 向右扩展的节点int dist_right = MAXDISTANCE;通过定义结点状态和发生器函数,就解决了8 数码问题的隐式图的生成问题。
八数码难题代码与基本思路 Eight puzzles
![八数码难题代码与基本思路 Eight puzzles](https://img.taocdn.com/s3/m/e27fb8ff551810a6f5248682.png)
图搜索求解八数码算法--A*算法(步程差) 一.流程框图二.算法基本原理拓展节点并计算步程差,如果是目标节点,成功并退出,如果不是,判断是否为优质节点,是则拓展为子节点,否则舍弃;判断深度是否越界,是则失败,未越界则继续拓展节点,若拓展表为空,则失败退出。
八数码结构体由矩阵Array,步程差Value,屏蔽方向Undirect和父节点指针*parent四部分组成,Array存放矩阵数字状态,Value存放估值函数值,Undirect记录上一步移动方向避免逆推,*parent记录父子关系用于寻径。
三.模块分析Getgraph 键盘输入获得初始数码组并返回Graph结构体指针。
Printgraph 输入八数码结构体地址,打印矩阵数字状态与当前步程差。
Evaluate 输入目标矩阵与当前矩阵,计算步程差并返回值。
Move 输入当前矩阵与移动方向Direct,移动并返回新结构体地址。
Search 输入起始结构体与目标结构体,尝试寻径并记录路径并返回终点地址(若成功)或返回空指针(若失败)。
Main 主函数,定义目标矩阵并调用函数。
四.源代码// Eight-figure puzzle// A*#include"stdafx.h"#include<stdio.h>#include<stdlib.h>#define N 3 //数码组长度#define MAX 50 //最大搜索深度typedefstruct node//八数码结构体{int array[N][N];//数码组int Value;//评估值int Undirect;//所屏蔽方向,防止往回推到上已状态,1上2下3左4右struct node *parent;//父节点}Graph;Graph *Storage[MAX]; //拓展节点存储队列Graph *path[MAX]; //路径堆栈Graph *GetGraph(Graph *New_graph) ////////自定义初始数码组{int x;for (x = 0; x <N; x++){scanf("%d %d %d", &New_graph->array[x][0], &New_graph->array[x][1],&New_graph->array[x][2]);}New_graph->Value = 30;New_graph->Undirect = 0;New_graph->parent = NULL;return New_graph;}void PrintGraph(Graph *point_graph) /////////打印数码组{int i, j;if (point_graph == NULL)printf("NULL\n");else{printf(" ---------------\n");for (i = 0; i<N; i++){printf("| ");for (j = 0; j<N; j++){printf("%d ", point_graph->array[i][j]);}printf("|");if (i==N-1)printf(" Value %d ", point_graph->Value);//评估函数值printf("\n");}printf(" ---------------\n");}}int Evaluate(Graph *point_graph, Graph *End_graph) /////////评价函数{int value = 0;//评估值int i, j,m ,n ;for (i = 0; i<N; i++){for (j = 0; j<N; j++){for (m = 0; m <N; m++){for (n = 0; n <N; n++){if (point_graph->array[i][j] == End_graph->array[m][n])value = value + abs(i - m) + abs(j - n); //数字当前位置与目标位置步程差之和}}}}point_graph->Value = value;return value;}Graph *Move(Graph *point_graph, int Direct) /////////移动数码组{Graph *New_graph;int BlankLocate = 0;//定位空格指示int Movable = 1;//移动有效int i, j, x0, y0, x, y;for (i = 0; i<N; i++)//空格坐标i,j{for (j = 0; j<N; j++){if (point_graph->array[i][j] == 0){BlankLocate = 1;break;}}if (BlankLocate == 1)break;}x0 = i;y0 = j;switch (Direct){case 1://上x0--;if (x0<0)Movable = 0;break;case 2://下x0++;if (x0 >= N)Movable = 0;break;case 3://左y0--;if (y0<0)Movable = 0;break;case 4://右y0++;if (y0 >= N)Movable = 0;break;}if (Movable == 0)//不能移动则返回原节点return point_graph;New_graph = (Graph *)malloc(sizeof(Graph));//生成节点for (x = 0; x<N; x++){for (y = 0; y<N; y++){New_graph->array[x][y] = point_graph->array[x][y];//复制数码组}}New_graph->array[i][j] = New_graph->array[x0][y0];New_graph->array[x0][y0] = 0;return New_graph;}Graph *Search(Graph *Begin, Graph *End) /////////搜索函数{Graph *St1, *St2, *ta;int Step = 0;//深度int Direct = 0;//方向int i;int front, rear;front = rear = -1;//队列初始化ta = NULL;rear++;//入队Storage[rear] = Begin;while (rear != front)//队列不空{front++;//出队St1 = Storage[front];for (i = 1; i <= 4; i++)//分别从四个方向推导出新子节点{Direct = i;if (Direct == St1->Undirect)//跳过屏蔽方向continue;St2 = Move(St1, Direct);//移动数码组if (St2 != St1)//数码组是否可以移动{Evaluate(St2, End);//评价新的节点sif (St2->Value == 0)//为0则搜索完成{St2->parent = St1;rear++;Storage[rear] = St2;//存储节点到待处理队列ta = St2;break;}if (St2->Value <= St1->Value + 1){St2->parent = St1;//st2->Undirect=Direct>2?(Direct==3)+3:(Direct==1)+1;/屏蔽方向switch (Direct)//设置屏蔽方向,防止往回推{case 1://上St2->Undirect = 2;break;case 2://下St2->Undirect = 1;break;case 3://左St2->Undirect = 4;break;case 4://右St2->Undirect = 3;break;}rear++;Storage[rear] = St2;//存储节点到待处理队列}else{free(St2);//抛弃劣质节点St2 = NULL;}}}if (ta != NULL)//为0则搜索完成break;Step++;//统计深度if (Step>=MAX){break;}}return ta;}int main(int argc, constchar * argv[]){// 8 1 3 7 4 5 6 2 0// 4 1 3 2 7 5 8 0 6// 4 5 1 2 7 3 0 8 6 //16 steps in fact but failed//目标数码组Graph End_graph = {{{ 1, 2, 3 },{ 8, 0, 4 },{ 7, 6, 5 }}, 0, 0, NULL};//初始数码组Graph New_graph;Graph *Begin_graph;printf("Enter initial matrix line by line\n For example:\t1 3 4 ENTER\n\t\t8 2 5 ENTER\n\t\t7 6 0 ENTER\n\n");Begin_graph = GetGraph(&New_graph);Evaluate(Begin_graph, &End_graph);printf("Initial matrix:\n");PrintGraph(Begin_graph);printf("Target matrix:\n");PrintGraph(&End_graph);Graph *W, *P;int top = -1;//图搜索W = Search(Begin_graph, &End_graph);if (W){P = W; //压栈while (P != NULL){top++;path[top] = P;P = P->parent;}printf("<<<<<< The Path >>>>>>\n");//弹栈打印while (top>-1){P = path[top];top--;PrintGraph(P);}printf("<<<<< Mission Complete >>>>>\n");system("pause");}else{printf("Path not found ,Search depth is %d\n", MAX);system("pause");}return 0;}五.运行结果将初始数码组改写为 2 5 4 3 7 1 8 6 ,定义某个数前面比他小的数个数为Xi,所有数字的Xi相加为Y,因为四向移动只可能改变Y的大小,不改变其奇偶性。
启发式搜索算法解决八数码问题(C语言)
![启发式搜索算法解决八数码问题(C语言)](https://img.taocdn.com/s3/m/bfc3270fdd3383c4ba4cd246.png)
1、程序源代码#include <stdio.h>#include<malloc.h>struct node{int a[3][3];//用二维数组存放8数码int hx;//函数h(x)的值,表示与目标状态的差距struct node *parent;//指向父结点的指针struct node *next;//指向链表中下一个结点的指针};//------------------hx函数-------------------//int hx(int s[3][3]){//函数说明:计算s与目标状态的差距值int i,j;int hx=0;int sg[3][3]={1,2,3,8,0,4,7,6,5};for(i=0;i<3;i++)for(j=0;j<3;j++)if(s[i][j]!=sg[i][j])hx++;return hx;}//-------------hx函数end----------------------////-------------extend扩展函数----------------//struct node *extend(node *ex){ //函数说明:扩展ex指向的结点,并将扩展所得结点组成一条//单链表,head指向该链表首结点,并且作为返回值int i,j,m,n; //循环变量int t; //临时替换变量int flag=0;int x[3][3];//临时存放二维数组struct node *p,*q,*head;head=(node *)malloc(sizeof(node));//headp=head;q=head;head->next=NULL;//初始化for(i=0;i<3;i++)//找到二维数组中0的位置{for(j=0;j<3;j++)if(ex->a[i][j]==0){flag=1;break;}if(flag==1)break;}for(m=0;m<3;m++)//将ex->a赋给xfor(n=0;n<3;n++)x[m][n]=ex->a[m][n];//根据0的位置的不同,对x进行相应的变换//情况1if(i-1>=0){t=x[i][j];x[i][j]=x[i-1][j];x[i-1][j]=t;flag=0;for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}//情况2for(m=0;m<3;m++)//将ex->a重新赋给x,即还原x for(n=0;n<3;n++)x[m][n]=ex->a[m][n];if(i+1<=2){t=x[i][j];x[i][j]=x[i+1][j];x[i+1][j]=t; flag=0;for(m=0;m<3;m++)for(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}//情况3for(m=0;m<3;m++)//将ex->a重新赋给x,即还原x for(n=0;n<3;n++)x[m][n]=ex->a[m][n];if(j-1>=0){t=x[i][j];x[i][j]=x[i][j-1];x[i][j-1]=t;flag=0;for(m=0;m<3;m++)for(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)//将x赋给afor(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}//情况4for(m=0;m<3;m++)//将ex->a重新赋给x,即还原xfor(n=0;n<3;n++)x[m][n]=ex->a[m][n];if(j+1<=2){t=x[i][j];x[i][j]=x[i][j+1];x[i][j+1]=t;flag=0;for(m=0;m<3;m++)for(n=0;n<3;n++)if(x[m][n]==ex->parent->a[m][n])flag++;if(flag!=9){q=(node *)malloc(sizeof(node));for(m=0;m<3;m++)for(n=0;n<3;n++)q->a[m][n]=x[m][n];q->parent=ex;q->hx=hx(q->a);q->next=NULL;p->next=q;p=p->next;}}head=head->next;return head;}//---------------extend函数end-----------------------////----------------insert函数-------------------------//node* insert(node *open,node * head){ //函数说明:将head链表的结点依次插入到open链表相应的位置, //使open表中的结点按从小到大排序。
实验三:A星算法求解8数码问题实验讲解
![实验三:A星算法求解8数码问题实验讲解](https://img.taocdn.com/s3/m/7c7729374693daef5ff73da7.png)
实验三:A*算法求解8数码问题实验一、实验目的熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解N数码难题,理解求解流程和搜索顺序。
二、实验内容1、八数码问题描述所谓八数码问题起源于一种游戏:在一个3×3的方阵中放入八个数码1、2、3、4、5、6、7、8,其中一个单元格是空的。
将任意摆放的数码盘(城初始状态)逐步摆成某个指定的数码盘的排列(目标状态),如图1所示:图1 八数码问题的某个初始状态和目标状态对于以上问题,我们可以把数码的移动等效城空格的移动。
如图1的初始排列,数码7右移等于空格左移。
那么对于每一个排列,可能的一次数码移动最多只有4中,即空格左移、空格右移、空格上移、空格下移。
最少有两种(当空格位于方阵的4个角时)。
所以,问题就转换成如何从初始状态开始,使空格经过最小的移动次数最后排列成目标状态。
2、八数码问题的求解算法盲目搜索宽度优先搜索算法、深度优先搜索算法启发式搜索启发式搜索算法的基本思想是:定义一个评价函数f,对当前的搜索状态进行评估,找出一个最有希望的节点来扩展。
先定义下面几个函数的含义:f*(n)=g*(n)+h*(n) (1)¥式中g*(n)表示从初始节点s到当前节点n的最短路径的耗散值;h*(n)表示从当前节点n到目标节点g的最短路径的耗散值,f*(n)表示从初始节点s经过n到目标节点g的最短路径的耗散值。
评价函数的形式可定义如(2)式所示:f(n)=g(n)+h(n) (2)其中n是被评价的当前节点。
f(n)、g(n)和h(n)分别表示是对f*(n)、g*(n)和h*(n)3个函数值的估计值。
利用评价函数f(n)=g(n)+h(n)来排列OPEN表节点顺序的图搜索算法称为算法A。
在A算法中,如果对所有的x,h(x)<=h*(x) (3)成立,则称好h(x)为h*(x)的下界,它表示某种偏于保守的估计。
采用h*(x)的下界h(x)为启发函数的A算法,称为A*算法。
python广度搜索解决八数码难题
![python广度搜索解决八数码难题](https://img.taocdn.com/s3/m/14b1cdd559f5f61fb7360b4c2e3f5727a5e9243c.png)
python⼴度搜索解决⼋数码难题—— ⼋数码难题 ——1.题⽬描述⼋数码问题也称为九宫问题。
在3×3的棋盘,摆有⼋个棋⼦,每个棋⼦上标有1⾄8的某⼀数字,不同棋⼦上标的数字不相同。
棋盘上还有⼀个空格,与空格相邻的棋⼦可以移到空格中。
要求解决的问题是:给出⼀个初始状态和⼀个⽬标状态,找出⼀种从初始状态转变成⽬标状态的移动棋⼦步数最少的移动步骤。
代码使⽤算法:⼴度搜索算法pythonimport numpy as npclass State:def __init__(self, state, directionFlag=None, parent=None):self.state = stateself.direction = ['up', 'down', 'right', 'left']if directionFlag:self.direction.remove(directionFlag)self.parent = parentself.symbol = ' 'def getDirection(self):return self.directiondef showInfo(self):for i in range(3):for j in range(3):print(self.state[i, j], end=' ')print("\n")print('->\n')returndef getEmptyPos(self):postion = np.where(self.state == self.symbol)return postiondef generateSubStates(self):if not self.direction:return []subStates = []boarder = len(self.state) - 1row, col = self.getEmptyPos()if 'left' in self.direction and col > 0:s = self.state.copy()temp = s.copy()s[row, col] = s[row, col-1]s[row, col-1] = temp[row, col]news = State(s, directionFlag='right', parent=self)subStates.append(news)if 'up' in self.direction and row > 0:s = self.state.copy()temp = s.copy()s[row, col] = s[row-1, col]s[row-1, col] = temp[row, col]news = State(s, directionFlag='down', parent=self)subStates.append(news)if 'down' in self.direction and row < boarder:s = self.state.copy()temp = s.copy()s[row, col] = s[row+1, col]s[row+1, col] = temp[row, col]news = State(s, directionFlag='up', parent=self)subStates.append(news)if self.direction.count('right') and col < boarder:s = self.state.copy()temp = s.copy()s[row, col] = s[row, col+1]s[row, col+1] = temp[row, col]news = State(s, directionFlag='left', parent=self)subStates.append(news)return subStatesdef solve(self):openTable = []closeTable = []openTable.append(self)steps = 1while len(openTable) > 0:n = openTable.pop(0)closeTable.append(n)subStates = n.generateSubStates()path = []for s in subStates:if (s.state == s.answer).all():while s.parent and s.parent != originState:path.append(s.parent)s = s.parentpath.reverse()return path, steps+1openTable.extend(subStates)steps += 1else:return None, Noneif __name__ == '__main__':symbolOfEmpty = ' 'State.symbol = symbolOfEmptyoriginState = State(np.array([[2, 8, 3], [1, 6 , 4], [7, symbolOfEmpty, 5]]))State.answer = np.array([[1, 2, 3], [8, State.symbol, 4], [7, 6, 5]])s1 = State(state=originState.state)path, steps = s1.solve()if path:for node in path:node.showInfo()print(State.answer)print("Total steps is %d" % steps)以上就是python⼴度搜索解决⼋数码难题的详细内容,更多关于python⼴度搜索⼋数码的资料请关注其它相关⽂章!。
八数码问题 算法流程
![八数码问题 算法流程](https://img.taocdn.com/s3/m/2e4e7b7cbc64783e0912a21614791711cd797910.png)
八数码问题算法流程下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。
文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by theeditor. I hope that after you download them,they can help yousolve practical problems. The document can be customized andmodified after downloading,please adjust and use it according toactual needs, thank you!In addition, our shop provides you with various types ofpractical materials,such as educational essays, diaryappreciation,sentence excerpts,ancient poems,classic articles,topic composition,work summary,word parsing,copy excerpts,other materials and so on,want to know different data formats andwriting methods,please pay attention!1. 问题定义:八数码问题是在一个 3x3 的棋盘上,有 8 个数字(1-8)和一个空格,通过移动空格,使得棋盘上的数字最终排列成目标状态。
c++算法 八数码问题
![c++算法 八数码问题](https://img.taocdn.com/s3/m/4eb96a933086bceb19e8b8f67c1cfad6195fe993.png)
c++算法八数码问题八数码问题是一种经典的智力游戏,其规则是在有限的格子中,按照一定的顺序将数字旋转移动到目标位置。
为了解决这个问题,我们可以使用算法的思想来设计一种有效的解决方案。
一、问题描述八数码问题是一个有N×N的棋盘,其中每个格子代表一个数字。
玩家需要按照一定的顺序旋转数字,将它们移动到目标位置。
目标位置是预先设定好的,玩家需要按照规则移动数字,使得棋盘上的数字按照正确的顺序排列。
二、算法思想为了解决八数码问题,我们可以使用贪心算法的思想。
首先,我们需要找到一个初始状态,这个状态应该是最简单、最容易解决的问题。
然后,我们通过循环迭代的方式,不断尝试不同的旋转方式,直到找到一个能够满足目标位置的解决方案。
三、C语言实现下面是一个简单的C语言实现,用于解决八数码问题。
这个程序使用了递归和回溯的方法,通过穷举所有可能的旋转方式来找到解决方案。
```c#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#define N 3// 定义棋盘状态结构体typedef struct {int nums[N][N];int num_count[N][N]; // 记录每个数字出现的次数} Board;// 判断两个数字是否相邻bool is_adjacent(int num1, int num2) {int dx[] = {-1, 0, 1};int dy[] = {0, -1, 1};for (int i = 0; i < 3; i++) {if (abs(nums[num1][i] - nums[num2][i]) <= 1) {return true;}}return false;}// 寻找最优解函数bool find_optimal_solution(Board& board, int target_row, int target_col) {// 初始化最优解为空状态bool optimal_solution = false;int optimal_score = INT_MAX; // 最优解的得分初始化为最大整数int best_score = INT_MAX; // 最优解的当前得分初始化为最大整数加一// 对当前棋盘进行遍历for (int row = 0; row < N; row++) {for (int col = 0; col < N; col++) {// 如果当前状态为空状态,则直接跳过if (board.nums[row][col] == 0) {continue;}// 记录当前状态的信息,包括得分和旋转次数等int score = calculate_score(board, row, col); // 计算得分函数在实现中定义了旋转方式的选择和得分计算规则等具体细节,这里省略了具体实现细节。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
“八数码问题求解”程序说明
(姓名:崔秋石学号:1080329038 班级:B0803291)
一、程序中使用到得算法
本程序用到了三种搜索算法,分别是BFS(广度优先搜索)、DFS(深度优先搜索)和A 算法。
A.BFS算法步骤:
1.每次搜索之前清空OPEN 、CLOSED、PATH三表,并初始化初始状态Initstate;
2.将初始节点放入OPEN表中;
3.判断初始和目标状态Goalstate是否相同,如是则成功退出;
4.将OPEN表中首端第一个节点取出放入CLOSED表中;
5.如果OPEN表为空,则失败退出。
否则用函数expandnodeBFS按Left,Right,Up,Down顺序扩展节点。
给子节点的深度赋值,定义其父节点和子节点的指针;
6.判断扩展后的子节点是否和目标节点相同,如是则成功退出,并用FindPath函数按照其父节点回溯到初始节点以寻找路径,并把所寻每一节点放入PATH表中;如果不相同,则把它放入OPEN表末端;
7.转步骤4。
广度优先搜索算法程序流程示意图
B.D FS算法步骤:
1.将初始节点S放入OPEN表中,若此节点为目标节点,则得解;
2.若OPEN表为空,则失败退出;
3.把OPEN表中首端第二个节点n移出,放入CLOSED表中;
4.若节点n的深度等于最大限制深度;则转向2;
5.扩展节点n,产生其全部子节点,并将它们放入OPEN表首端,并给出返回n的指针,若节点不能扩展,则转向2;
6.若后继子节点中有目标节点,则得解,成功退出。
深度优先搜索算法程序流程示意图
C.H euristic A算法步骤:
1.每次搜索之前清空OPEN 、CLOSED、PATH三表,并初始化初始状态Initstate;
2.将初始节点放入OPEN表中;
3.判断初始和目标状态Goalstate是否相同,如是则成功退出;
4.从OPEN表中找到估价值最小的节点(函数Evaluate)将其取出放入CLOSED表中。
5.如果OPEN表为空,则失败退出。
否则用函数expandHeuristic按Left,Right,Up,Down顺序扩展节点。
给子节点的深度赋值,定义其父节点和子节点的指针;
6.判断扩展后的子节点是否和目标节点相同,如是则成功退出,并用FindPath函数按照其父节点回溯到初始节点以寻找路径,并把所寻每一节点放入PATH表中;如果不是,则判断子节点是否已在CLOSED表和OPEN表中,如果都不在,则放入OPEN 表末端;
7.转步骤4。
启发式搜索算法程序流程示意图
二、程序数据结构描述
1.节点状态表示:
定义结构体
struct Eightpuzzle{
int depthcurrent;//节点深度
int state[9];//节点状态
struct Eightpuzzle * father;//节点的父节点
struct Eightpuzzle * child;//节点的子节点
};
2.OPEN表CLOSED表:
用MFC中CList类定义
CPtrList Open;//OPEN表
CPtrList Closed;//CLOSED表
CPtrList Path;//用于最后存放路径PA TH表
三、函数说明
1.估价函数int Evaluate(Eightpuzzle* current,Eightpuzzle* goal)
返回一个int型数值,计算状态current中每个格子的号码与goal中相应号码之间的距离之和。
取f(n)=d(n)+h(n),h(n)=P(n);
2.enum direction {LEFT, RIGHT, UP, DOWN,INV ALID};
direction MoveDirection(Eightpuzzle *father,Eightpuzzle *child,int &x);
定义枚举类型direction,判断返回节点扩展时可以移动的方向。
3.主要函数一览:
public:
bool NumberCheck(int state[9]);//检查数据有效性
bool Ishavepath(Eightpuzzle *initial, Eightpuzzle *goal);//检查时候有路径
bool SearchHeuristic();//启发式搜索
bool SearchBFS();//广度优先搜索
bool SearchDFS();//深度优先搜索
int Evaluate(Eightpuzzle* current,Eightpuzzle* goal);//计算估价函数取P(n)
Eightpuzzle Initstate;//初始节点
Eightpuzzle Goalstate;//目标节点
CPtrList Open;//OPEN表
CPtrList Closed;//CLOSED表
CPtrList Path;//用于最后存放路径PA TH表
int m_ndepth;
Eightpuzzle *currentstep;
private:
enum direction {LEFT, RIGHT, UP, DOWN,INV ALID};
void FindPath(Eightpuzzle *finalnode, Eightpuzzle *initnode);//按各节点父节点寻找路径direction MoveDirection(Eightpuzzle *father,Eightpuzzle *child,int &x);//判断可移动方向bool IsinClosed(Eightpuzzle *curnode);//判断当前扩展的节点是否已存在CLOSED表中bool IsinOpen(Eightpuzzle* curnode);//判断当前扩展的节点是否已存在OPEN表中
bool Comparestate(Eightpuzzle * stateone,Eightpuzzle * stateanother);//比较两个节点状态时候相同
void Copy8puzzle(Eightpuzzle *stateone, Eightpuzzle *stateanother);//复制节点状态
bool MovetoDown(Eightpuzzle *fatherstate, Eightpuzzle *childstate);//向下移动
bool MovetoUp(Eightpuzzle *fatherstate, Eightpuzzle *childstate);//向上移动
bool MovetoRight(Eightpuzzle *fatherstate, Eightpuzzle *childstate);//向右移动
bool MovetoLeft(Eightpuzzle *fatherstate, Eightpuzzle *childstate);//向左移动
bool expandnodeBFS(Eightpuzzle *newnode,Eightpuzzle *nodeN,Eightpuzzle* pinit);//广度优先搜索中扩展节点
bool expandnodeDFS(Eightpuzzle *newnode,Eightpuzzle *nodeN,Eightpuzzle* pinit);//深度优先搜索中扩展节点
bool expandnodeHeuristic(Eightpuzzle * newnode,Eightpuzzle* pstart);//启发式搜索中扩展节点
四、改进方向
此次作业使我对人工智能的搜索原理及其算法有了更深刻的理解,认识到了启发性搜索中估价函数的重要性。
第一次写程序遇到了很多困难,参考了一些资料,请教了师兄和一些同学,感谢他们的帮助。
对程序中算法实现方法的认识还比较浅显,运用MFC完成界面设计的过程中,数据输入这方面采用的方法还很笨拙,有待进一步提高。