启发式搜索算法解决八数码问题(C语言)
C语言实现8数码问题

1、实验目的(1)熟悉人工智能系统中的问题求解过程;(2)熟悉状态空间中的盲目搜索策略;(3)掌握盲目搜索算法,重点是宽度优先搜索和深度优先搜索算法。
2、实验要求用VC语言编程,采用宽度优先搜索和深度优先搜索方法,求解8数码问题3、实验内容(1)采用宽度优先算法,运行程序,要求输入初始状态假设给定如下初始状态S02 8 31 6 47 0 5和目标状态Sg2 1 64 0 87 5 3验证程序的输出结果,写出心得体会。
(2)对代码进行修改(选作),实现深度优先搜索求解该问题提示:每次选扩展节点时,从数组的最后一个生成的节点开始找,找一个没有被扩展的节点。
这样也需要对节点添加一个是否被扩展过的标志。
4 源代码及实验结果截图#include<stdio.h>#include<stdlib.h>#include<math.h>//八数码状态对应的节点结构体struct Node{int s[3][3];//保存八数码状态,0代表空格int f,g;//启发函数中的f和g值struct Node * next;struct Node *previous;//保存其父节点};int open_N=0; //记录Open列表中节点数目//八数码初始状态int inital_s[3][3]={2,8,3,1,6,4,7,0,5};//八数码目标状态int final_s[3][3]={2,1,6,4,0,8,7,5,3};//------------------------------------------------------------------------//添加节点函数入口,方法:通过插入排序向指定表添加//------------------------------------------------------------------------void Add_Node( struct Node *head, struct Node *p){struct Node *q;if(head->next)//考虑链表为空{ q = head->next;if(p->f < head->next->f){//考虑插入的节点值比链表的第一个节点值小p->next = head->next;head->next = p;}else {while(q->next)//考虑插入节点x,形如a<= x <=b{if((q->f < p->f ||q->f == p->f) && (q->next->f > p->f || q->next->f == p->f)){ p->next = q->next;q->next = p;break;}q = q->next;}if(q->next == NULL) //考虑插入的节点值比链表最后一个元素的值更大q->next = p;}else head->next = p;}//------------------------------------------------------------------------//删除节点函数入口//------------------------------------------------------------------------void del_Node(struct Node * head, struct Node *p ){struct Node *q;q = head;while(q->next){if(q->next == p){q->next = p->next;p->next = NULL;if(q->next == NULL) return;// free(p);}q = q->next;}}//------------------------------------------------------------------------//判断两个数组是否相等函数入口//------------------------------------------------------------------------int equal(int s1[3][3], int s2[3][3])int i,j,flag=0;for(i=0; i< 3 ; i++)for(j=0; j< 3 ;j++)if(s1[i][j] != s2[i][j]){flag = 1; break;}if(!flag)return 1;else return 0;}//------------------------------------------------------------------------//判断后继节点是否存在于Open或Closed表中函数入口//------------------------------------------------------------------------int exit_Node(struct Node * head,int s[3][3], struct Node *Old_Node) {struct Node *q=head->next;int flag = 0;while(q)if(equal(q->s,s)) {flag=1;Old_Node->next = q;return 1;}else q = q->next;if(!flag) return 0;}//------------------------------------------------------------------------//计算p(n)的函数入口//其中p(n)为放错位的数码与其正确的位置之间距离之和//具体方法:放错位的数码与其正确的位置对应下标差的绝对值之和//------------------------------------------------------------------------int wrong_sum(int s[3][3]){int i,j,fi,fj,sum=0;for(i=0 ; i<3; i++)for(j=0; j<3; j++){for(fi=0; fi<3; fi++)for(fj=0; fj<3; fj++)if((final_s[fi][fj] == s[i][j])){sum += fabs(i - fi) + fabs(j - fj);break;}}return sum;}//------------------------------------------------------------------------//获取后继结点函数入口//检查空格每种移动的合法性,如果合法则移动空格得到后继结点//------------------------------------------------------------------------int get_successor(struct Node * BESTNODE, int direction, struct Node *Successor)//扩展BESTNODE,产生其后继结点SUCCESSOR {int i,j,i_0,j_0,temp;for(i=0; i<3; i++)for(j=0; j<3; j++)Successor->s[i][j] = BESTNODE->s[i][j];//获取空格所在位置for(i=0; i<3; i++)for(j=0; j<3; j++)if(BESTNODE->s[i][j] == 0){i_0 = i; j_0 = j;break;} switch(direction){case 0: if((i_0-1)>-1 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0-1][j_0];Successor->s[i_0-1][j_0] = temp;return 1;}else return 0;case 1: if((j_0-1)>-1){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0-1];Successor->s[i_0][j_0-1] = temp;return 1;}else return 0;case 2: if( (j_0+1)<3){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0][j_0+1];Successor->s[i_0][j_0+1] = temp;return 1;}else return 0;case 3: if((i_0+1)<3 ){temp = Successor->s[i_0][j_0];Successor->s[i_0][j_0] = Successor->s[i_0+1][j_0];Successor->s[i_0+1][j_0] = temp;return 1;}else return 0;}}//------------------------------------------------------------------------//从OPen表获取最佳节点函数入口//------------------------------------------------------------------------struct Node * get_BESTNODE(struct Node *Open){return Open->next;}//------------------------------------------------------------------------//输出最佳路径函数入口//------------------------------------------------------------------------void print_Path(struct Node * head){struct Node *q, *q1,*p;int i,j,count=1;p = (struct Node *)malloc(sizeof(struct Node));//通过头插法变更节点输出次序p->previous = NULL;q = head;while(q){q1 = q->previous;q->previous = p->previous;p->previous = q;q = q1;}q = p->previous;while(q){if(q == p->previous)printf("八数码的初始状态:\n");else if(q->previous == NULL)printf("八数码的目标状态:\n");else printf("八数码的中间态%d\n",count++);for(i=0; i<3; i++)for(j=0; j<3; j++){printf("%4d",q->s[i][j]);if(j == 2)printf("\n");}printf("f=%d, g=%d\n\n",q->f,q->g);q = q->previous;}}//------------------------------------------------------------------------//A*子算法入口:处理后继结点//------------------------------------------------------------------------void sub_A_algorithm(struct Node * Open, struct Node * BESTNODE, struct Node * Closed,struct Node *Successor){struct Node * Old_Node = (struct Node *)malloc(sizeof(struct Node));Successor->previous = BESTNODE;//建立从successor返回BESTNODE的指针Successor->g = BESTNODE->g + 1;//计算后继结点的g值//检查后继结点是否已存在于Open和Closed表中,如果存在:该节点记为old_Node,比较后继结点的g值和表中old_Node节点//g值,前者小代表新的路径比老路径更好,将Old_Node的父节点改为BESTNODE,并修改其f,g值,后者小则什么也不做。
八数码问题C语言A星算法详细实验报告含代码

一、实验内容和要求八数码问题:在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格是空的,其初始状态如图1所示,要求对空格执行空格左移、空格右移、空格上移和空格下移这四个操作使得棋盘从初始状态到目标状态。
例如:图1 八数码问题示意图请任选一种盲目搜索算法(广度优先搜索或深度优先搜索)或任选一种启发式搜索方法(全局择优搜索,加权状态图搜索,A 算法或A* 算法)编程求解八数码问题(初始状态任选)。
选择一个初始状态,画出搜索树,填写相应的OPEN 表和CLOSED表,给出解路径,对实验结果进行分析总结,得出结论。
二、实验目的1. 熟悉人工智能系统中的问题求解过程;2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用;3. 熟悉对八数码问题的建模、求解及编程语言的应用。
三、实验算法A*算法是一种常用的启发式搜索算法。
在A*算法中,一个结点位置的好坏用估价函数来对它进行评估。
A*算法的估价函数可表示为:f'(n) = g'(n) + h'(n)这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值(也称为最小耗费或最小代价),h'(n)是n到目标的最短路经的启发值。
由于这个f'(n)其实是无法预先知道的,所以实际上使用的是下面的估价函数:f(n) = g(n) + h(n)其中g(n)是从初始结点到节点n的实际代价,h(n)是从结点n到目标结点的最佳路径的估计代价。
在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。
用f(n)作为f'(n)的近似,也就是用g(n)代替g'(n),h(n)代替h'(n)。
这样必须满足两个条件:(1)g(n)>=g'(n)(大多数情况下都是满足的,可以不用考虑),且f必须保持单调递增。
(2)h必须小于等于实际的从当前节点到达目标节点的最小耗费h(n)<=h'(n)。
启发式搜索浅谈,解决八数码问题

启发式搜索浅谈,解决⼋数码问题博客迁移⾄相信很多⼈都接触过九宫格问题,也就是⼋数码问题。
问题描述如下:在3×3的棋盘,摆有⼋个棋⼦,每个棋⼦上标有1⾄8的某⼀数字,不同棋⼦上标的数字不相同。
棋盘上还有⼀个空格,与空格相邻的棋⼦可以移到空格中。
要求解决的问题是:给出⼀个初始状态和⼀个⽬标状态,找出⼀种从初始转变成⽬标状态的移动棋⼦步数最少的移动步骤。
其实在很早之前我就做过这道题了,当时我⽤的是双向⼴搜,后来⼜⼀知半解的模仿了⼀个启发式搜索(A*)。
昨天在图书馆看书的时候,翻阅了⼀下⼈⼯智能的书籍,⼜发现了这个经典的⼋数码问题。
于是便看了下去,渐渐的明⽩了启发式搜索的真正含义,才知道⾃⼰⼏年前模仿的那个代码是什么意思。
在这篇⽂章⾥,我把昨天的所学东西稍稍的记录⼀下,顺便分享给⼤家,如果有什么错误,欢迎各位指出。
平时,我们所使⽤的搜索算法⼤多数都是⼴搜(BFS)和深搜(DFS),其实他们都是盲⽬搜索,相对来说搜索的状态空间⽐较⼤,效率⽐较低。
⽽启发式搜索则相对的智能⼀些,它能对所有当前待扩展状态进⾏评估,选出⼀个最好的状态、最容易出解的状态进⾏搜索。
这样,我们就可以避免扩展⼤量的⽆效状态,从⽽提⾼搜索效率。
在对状态进⾏评估的时候,我们会使⽤到⼀个这样的等式f(n)=g(n)+h(n)。
那这个等式是什么含义呢?其中g(n)代表到达代价,即从初始状态扩展到状态n的代价值。
h(n)代表状态n的估计出解代价,即从状态n扩展到⽬标状态的代价估计值。
所以,f(n)代表估计整体代价,即⼀个搜索路径上经过状态n且成功出解的估计代价值。
于是,在启发式搜索算法中,我们只要对每⼀个状态,求出其f(n),每次取f(n)最⼩的状态进⾏扩展即可。
那现在还有⼀个问题,就是如何确定g(n)和h(n)到底是什么函数?否则f(n)也⽆法求出。
其实g(n)相对来说⽐较好确定,因为在到达状态n之后,必定有⼀条从初始状态到n的搜索路径,于是我们可以从这条路径上找出到达代价g(n),⼀般的我们就取路径长度即可。
基于启发式搜索算法A星解决八数码问题

int statue[size][size]; //记录当前节点的状态 struct Node * Tparent; //用来构成搜索树,该树由搜索图的反向指针构成 struct Node * opennext; //用来构成 open 表,该指针指向该节点在 open 表中的下一个 节点 struct Node * closenext; //用来构成 open 表,该指针指向该节点在 close 表中的下一个 节点 struct Node * brothernext; //构成兄弟链表,该指针指向该节点在兄弟链表中的下一个节 点 int f; //记录当前节点的 f 函数值 int g; //记录当前节点的 g 函数的值 int h; //记录当前节点的 h 函数的值 };
5
get_bestroute (bestNode); return; }
2.2.7 生成 bestNode 所指节点的后继节点
定义一个后继节点链表,表头为 head_b,将 bestNode 所指节点的不是前驱节点的后继 节点,链接到后继及诶单链表中。getchild 函数可以实现这个功能。
//产生 bestNode 的一切后继节点。。 head head_b; //定义 bestNode 的后继节点表 head_b.next=NULL; getchild (&head_b,bestNode); //产生 bestNode 的子节点,将不是 bestNode 的父节点的
while (head_b.next!=NULL) { Node *tmp=getbrother (&head_b); //从后继节点表中取出一个节点记为 tmp,并从
八数码实验报告

八数码实验报告实验名称:八数码实验目的:通过使用搜索算法和启发式算法,解决八数码问题,深入理解搜索算法原理和应用。
实验环境:使用Python语言进行编程实现,操作系统为Windows。
实验过程:1. 定义八数码问题的状态和目标状态,分别以列表的形式表示。
* 初始状态:[2, 8, 3, 1, 6, 4, 7, 0, 5]* 目标状态:[1, 2, 3, 8, 0, 4, 7, 6, 5]2. 实现深度优先搜索算法,运行程序得到结果。
通过深度优先搜索算法,得到了八数码问题的解法。
但是,由于深度优先搜索算法过于盲目,搜索时间过长,而且容易陷入无解状态,因此需要改进算法。
3. 改进算法——广度优先搜索。
在深度优先搜索的基础上,改用广度优先搜索算法,实现代码如下:```def bfs(start, target):queue = [(start, [start])]seen = {tuple(start)}while queue:node, path = queue.pop(0)for move, i in direction.items():new_node = [j for j in node]if i not in range(0, 9):continuenew_node[0], new_node[i] = new_node[i], new_node[0] if tuple(new_node) in seen:continueif new_node == target:return path + [new_node]seen.add(tuple(new_node))queue.append((new_node, path + [new_node]))```4. 改进算法——A*算法。
在广度优先搜索的基础上,使用A*算法进行优化。
进行了以下改进:* 引入估价函数,加快搜索速度;* 遍历过程中对结点进行评估,保留最优的结点。
八个数字问题实验报告.doc

八个数字问题实验报告. 《八数码问题》实验报告首先,实验的目的:熟悉启发式搜索算法。
二、实验内容:启发式搜索算法用于解决8位数问题。
编制了程序,实现了解决8位数问题的算法。
采用评估功能,其中:是搜索树中节点的深度;在节点数据库中放错位置的件数;这是每个棋子与其在节点数据库中的目标位置之间距离的总和。
三、实验原理:1.问题描述:八位数问题也被称为九宫问题。
在3×3的棋盘上,有八个棋子,每一个棋子都标有一定的1到8的数字,不同棋子上标的数字是不同的。
棋盘上还有一个空格(用数字0表示),与空格相邻的棋子可以移动到空格中。
要解决的问题是: 给定初始状态和目标状态,找出从初始状态到目标状态移动次数最少的移动步骤。
所谓问题的一种状态是棋盘上棋子的排列。
解决八位数问题实际上是找出一系列从初始状态到目标状态的中间过渡状态。
2.原则描述:启发式搜索(1)原理启发式搜索是评估每个搜索在状态空间中的位置以获得最佳位置,然后从这个位置搜索到目标。
这样,可以省略大量不必要的搜索路径,并且提高了效率。
在启发式搜索中,位置的评估非常重要。
不同的评估会产生不同的效果。
(2)评估函数计算节点的评估函数,可分为两部分:1.成本已经支付(从开始节点到当前节点);2.要支付的价格(当前节点到目标节点)。
节点n的评估函数被定义为从初始节点通过n到目标节点的路径的最小成本的估计值,即=。
是从初始节点到达当前节点n的实际成本;是从节点n到目标节点的最佳路径的估计开销。
比例越大,它越倾向于先搜索宽度或同等成本。
相反,比例越大,启发式性能越强。
(3)算法描述:(1)将起始节点S放入OPEN表中,计算节点S的值;(2)如果OPEN为空表,则无法退出且没有解决方案;(3)从OPEN表中选择具有最小值的节点。
如果多个节点具有相同的值,当其中一个节点是目标节点时,选择目标节点;否则,任意一个节点被选为节点;(4)从OPEN表中移除节点,并将其放入CLOSED扩展节点表中;(5)如果它是目标节点,它成功退出并获得解决方案;⑥扩展节点以生成其所有后续节点。
八数码问题C语言代码

八数码问题源程序及注释:#include<stdio.h>#include<conio.h>int n,m;typedef struct Node{char matrix[10];/*存储矩阵*/char operate;/*存储不可以进行的操作,L代表不能左移R代表不能右移U代表不能上移D代表不能下移*/char extend;/*是否可以扩展,Y代表可以,N代表不可以*/int father;/*指向产生自身的父结点*/}Node;char start[10]={"83426517 "};/*此处没有必要初始化*/char end[10]={"1238 4765"};/*此处没有必要初始化*/Node base[4000];int result[100];/*存放结果的base数组下标号,逆序存放*/int match()/*判断是否为目标*/{int i;for(i=0;i<9;i++){if(base[n-1].matrix[i]!=end[i]){return 0;}}return 1;}void show()/*显示矩阵的内容*/{int i=1;while(m>=0){int mm=result[m];//clrscr();printf("\n\n\n 状态方格\t\t步骤 %d",i);printf("\n\n\n\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[0],base[mm].mat rix[1],base[mm].matrix[2]);printf("\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[3],base[mm].matrix[4],base[mm].matrix[5]);printf("\n\n\t\t\t%c\t%c\t%c\n",base[mm].matrix[6],base[mm].matrix[7] ,base[mm].matrix[8]);//sleep(1);m--;i++;}}void leave()/*推理成功后退出程序之前要执行的函数,主要作用是输出结果*/ {n--;while(base[n].father!=-1){result[m]=n;m++;n=base[n].father;}result[m]=0;result[m+1]='\0';show();//clrscr();printf("\n\n\n\n\n\n\n\n\n\t\t\t\t搜索结束\n\n\n\n\n\n\n\n\n\n"); getch();//exit(0);}int left(int x)/*把下标为X的数组中的矩阵的空格左移*/{int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==0||i==3||i==6||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i-1];base[n].matrix[i-1]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='R';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}int right(int x)/*把下标为X的数组中的矩阵的空格右移*/ {int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==2||i==5||i==8||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i+1];base[n].matrix[i+1]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='L';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}int up(int x)/*把下标为X的数组中的矩阵的空格上移*/ {int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==0||i==1||i==2||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i-3];base[n].matrix[i-3]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='D';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}int down(int x)/*把下标为X的数组中的矩阵的空格下移*/ {int i,j;char ch;for(i=0;i<9;i++){if(base[x].matrix[i]==' ')break;}if(i==6||i==7||i==8||i==9){return 0;}for(j=0;j<9;j++){base[n].matrix[j]=base[x].matrix[j];}ch=base[n].matrix[i+3];base[n].matrix[i+3]=base[n].matrix[i];base[n].matrix[i]=ch;base[n].operate='U';base[n].extend='Y';base[n].father=x;base[x].extend='N';n++;if(match(i))leave();return 1;}main(){int i;char a[20],b[20];n=1;//textcolor(LIGHTGREEN);//clrscr();/*以下是输入初始和目标矩阵,并把输入的0转换为空格*/ printf("Please input the start 9 chars:");scanf("%s",a);printf("Please input the end 9 chars:");scanf("%s",b);for(i=0;i<9;i++){if(a[i]=='0'){start[i]=' ';continue;}if(b[i]=='0'){end[i]=' ';continue;}start[i]=a[i];end[i]=b[i];}start[9]='\0';end[9]='\0';for(i=0;i<9;i++){base[0].matrix[i]=start[i];}base[0].operate='N';base[0].extend='Y';base[0].father=-1;/*以上是为第一个base数组元素赋值*/for(i=0;n<4000;i++){if(base[i].extend=='Y'){if(base[i].operate=='L'){right(i);up(i);down(i);}if(base[i].operate=='R'){left(i);up(i);down(i);}if(base[i].operate=='U'){left(i);right(i);down(i);}if(base[i].operate=='D'){left(i);right(i);up(i);}if(base[i].operate=='N'){left(i);right(i);up(i);down(i); }}}}。
C语言类似启发式八数码

#include<stdio.h>#include<stdlib.h>#define null 0static int target[3][3]={1,2,3,8,0,4,7,6,5};//记录最终状态static int K=0;struct node{ int data[3][3]; //定义八数码的初始状态int not_in_position_num; //定义不在正确位置八数码的个数int deapth; //定义了搜索的深度int eva_function; //评价函数的值,每次选取最小的进行扩展struct node *parent;//父节点struct node *next;//下一个节点int end;//表示是否已经扩展,为0未扩展};int not_in_position_num(int s[3][3]) //函数说明:计算s与目标状态的差距值{int i,j;int not_in_position_num=0;for(i=0;i<3;i++)for(j=0;j<3;j++)if(s[i][j]!=target[i][j]){not_in_position_num++;}return not_in_position_num;}int eight_numpara(node *top)//计算启发函数的值{if(top->parent==null )top->deapth=0;elsetop->deapth=top->parent->deapth+1;return top->eva_function=top->not_in_position_num+top->deapth;}node* Into(node *Parent, int x[3][3])//生成一个节点{node *p;p=(node *)malloc(sizeof(node));int i,j;for(i=0;i<3;i++)for(j=0;j<3;j++)p->data[i][j]=x[i][j];p->not_in_position_num=not_in_position_num(x);p->parent=Parent;p->eva_function=eight_numpara(p);p->end=0;return p;}int existed(node *head,int x[3][3])//判断节点是否存在过,先判断这个数是否存在过{int key=1;//未出现过int flag=0;int m,n;struct node *q=head->next;while(q!=null){flag=0;for(m=0;m<3;m++)for( n=0;n<3;n++){if(x[m][n]==q->data[m][n])flag++;}if(flag==9){key=0;//出现过return key;}elseq=q->next;}return key;}node *findleaf(node *head)//寻找估价函数最小的节点{struct node *p=head->next;while(p!=null){if(p->end==1)p=p->next;elsebreak;}struct node *q;q=p;int flag=p->eva_function;while(p!=null){if((p->eva_function<flag)&&(p->end!=1 )){flag=p->eva_function;q=p;}elsep=p->next;}q->end=1;//标志这个节点已经扩展过了return q;}void Print(node *head){int m,n;node *p=head->next;printf("依次输出链表节点\n");while(p!=null){printf("-----------------------------\n");for(m=0;m<3;m++){ for( n=0;n<3;n++){printf("%d\t",p->data[m][n]);}printf("\n");}printf("\n");printf("与目标节点相差:%d\n",p->not_in_position_num);printf("深度为:%d\n",p->deapth);printf("启发函数值:%d\n",p->eva_function);printf("-----------------------------\n");p=p->next;}printf("-----------------------------\n");}void print(node *head)//输出节点数据{int m,n;node *p=head->next;while(p->next!=null){p=p->next;}printf("输出最终结果\n");while(p!=null){printf("-----------------------------\n");for(m=0;m<3;m++){ for( n=0;n<3;n++){printf("%d\t",p->data[m][n]);}printf("\n");}printf("-----------------------------\n" );p=p->parent;}}node *extend(node *head){int i,j,m,n; //循环变量int key;//判断是否出现过,默认未出现过int t;int flag=0;int x[3][3];//临时存放二维数组node *open=head;//指向最后一个节点node *p;node *q;//存储刚生成的节点while(open->next!=null){open=open->next;}p=findleaf(head);//找到代价最小的节点for(i=0;i<3;i++)//找到二维数组中0的位置{for(j=0;j<3;j++)if(p->data[i][j]==0){flag=1;break;}if(flag==1)break;}//情况1for(m=0;m<3;m++)for(n=0;n<3;n++)x[m][n]=p->data[m][n];if(i-1>=0){t=x[i][j];x[i][j]=x[i-1][j];x[i-1][j]=t;key=existed(head,x);if(key==1)//判断是否出现过{q=Into(p,x);//生成一个节q->next=open->next;open->next=q;open=open->next;if(q->not_in_position_num==0){K=1;return head;}}}//情况2for(m=0;m<3;m++)//还原xfor(n=0;n<3;n++)x[m][n]=p->data[m][n];if(i+1<=2){t=x[i][j];x[i][j]=x[i+1][j];x[i+1][j]=t;key=existed(head,x);if(key==1){q=Into(p,x);q->next=open->next;open->next=q;open=open->next;if(q->not_in_position_num==0){K=1;return head;}}}//情况3for(m=0;m<3;m++)//还原xfor(n=0;n<3;n++)x[m][n]=p->data[m][n];if(j-1>=0){t=x[i][j];x[i][j]=x[i][j-1];x[i][j-1]=t;key=existed(head,x);if(key==1){q=Into(p,x);q->next=open->next;open->next=q;open=open->next;if(q->not_in_position_num==0){K=1;return head;}}}//情况4for(m=0;m<3;m++)//还原xfor(n=0;n<3;n++)x[m][n]=p->data[m][n];if(j+1<=2){t=x[i][j];x[i][j]=x[i][j+1];x[i][j+1]=t;key=existed(head,x);if(key==1){q=Into(p,x);q->next=open->next;open->next=q;open=open->next;if( q->not_in_position_num==0){K=1;return head;}}}return head;}void main(){int x[3][3];int i,j;printf("请输入初始状态的8数码(按每行从左往右依次输入,用0表示空格):\n");for(i=0;i<3;i++)for(j=0;j<3;j++)scanf("%d",&x[i][j]);node *head=null;head=(node *)malloc(sizeof(node));head->next=null;head->parent=null;//生成头结点node *newlist=(node *)malloc(sizeof(node));//生成第一个节点node *p=head;newlist->next=head->next;head->next=newlist;newlist->deapth=0;for(i=0;i<3;i++)for(j=0;j<3;j++)newlist->data[i][j]=x[i][j];newlist->not_in_position_num=not_in_position_num(x);newlist->eva_function=newlist->not_in_position_num;newlist->parent=null;newlist->end=0;while(K!=1){extend(head);}Print(head);print(head); }。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
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表中的结点按从小到大排序。
函数返回open指针node *p,*q;//p、q均指向open表中的结点,p指向q所指的前一个结点int i,j;int flag=0;if(open==NULL)//初始状态,open表为空{ //首先将head表第一个结点直接放入open表中open=head;q=head;head=head->next;q->next=NULL;//再插入第二个结点if(head->hx<open->hx){//插入到首结点位置open=head;head=head->next;open->next=q;}else{ //或者第二个结点的位置q->next=head;head=head->next;q=q->next;q->next=NULL;p=open;}p=open;q=open->next;} //end ifwhile(head!=NULL){q=open;if(head->hx<open->hx) //插入到表头{open=head;head=head->next;open->next=q;continue;}else { q=q->next;p=open;} //否则,q指像第二个结点,p指向q前一个结点while(q->next!=NULL) //将head的一个结点插入到链表中(非表尾的位置){if(q->hx<head->hx){q=q->next;p=p->next;}else{p->next=head;head=head->next;p->next->next=q;break;}}if(q->next==NULL)//将head的一个结点插入到表尾{if(q->hx>head->hx){p->next=head;head=head->next;p->next->next=q;}else{q->next=head;head=head->next;q->next->next=NULL;}}//if}//whilereturn open;}//insert//-----------------insert函数end--------------------////---------------------main-----------------------//void main(){int i,j;node s0;node *open,*close;node *p,*q;node *newlist;printf("请输入初始状态的8数码(按每行从左往右依次输入,用0表示空格):\n");for(i=0;i<3;i++)for(j=0;j<3;j++)scanf("%d",&s0.a[i][j]);s0.parent=(node *)malloc(sizeof(node));s0.parent->hx=9;s0.hx=hx(s0.a);open=&s0;p=&s0;if(open->hx==0){printf("该状态已为最终状态!\n");return;}q=&s0;close=&s0;open=NULL;newlist=extend(q);//newlist指向新扩展出来的链表open=insert(open,newlist);//将扩展出来的结点插入到open表中while(1){q->next=open;//q始终指向close表尾结点。
将open表的第一个元素加到close表open=open->next;q=q->next;q->next=NULL;if(q->hx==0){printf("\n搜索成功!\n");break;}newlist=extend(q);//对close表最后一个结点进行扩展,扩展得到的链表接到open 表尾open=insert(open,newlist);//将扩展的结点按顺序插入到open表中}p=close;printf("择优搜索过程如下:\n");while(p!=NULL){for(i=0;i<3;i++){for(j=0;j<3;j++)printf("%d ",p->a[i][j]);printf("\n");}printf("\n");p=p->next;}}2、程序运行结果截图截图1:初始态为:2 8 31 47 6 5运行结果如右图所示:截图2:初始状态为 2 8 3 时,程序运行结果如下:1 6 47 5。