八数码宽度优先搜索
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值,后者小则什么也不做。
用盲目搜索技术解决八数码问题

.用盲目搜索技术解决八数码问题题目在3×3的棋盘,有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。
棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。
要解决的问题是:任意给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
算法流程使用宽度优先搜索从初始节点开始,向下逐层对节点进形依次扩展,并考察它是否为目标节点,再对下层节点进行扩展(或搜索)之前,必须完成对当层的所有节点的扩展。
再搜索过程中,未扩展节点表OPEN中的节点排序准则是:先进入的节点排在前面,后进入的节点排在后面。
宽度优先算法如下:把初始结点S0放入OPEN表中若OPEN表为空,则搜索失败,问题无解取OPEN表中最前面的结点N放在CLOSE表中,并冠以顺序编号n若目标结点,则搜索成功,问题有解N?Sg若N无子结点,则转2扩展结点N,将其所有子结点配上指向N的放回指针,依次放入OPEN表的尾部,转2源程序#include <iostream>文档Word.#include <ctime>#include <vector>using namespace std;const int ROW = 3;//行数const int COL = 3;//列数const int MAXDISTANCE = 10000;//最多可以有的表的数目const int MAXNUM = 10000;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;Node src, dest;// 父节表目的表vector<Node> node_v; // store the nodes存储节点文档Word.bool isEmptyOfOPEN() //open表是否为空for (int i = 0; i < node_v.size(); i++) {if (node_v[i].dist != MAXNUM)return false;}return true;}bool isEqual(int index,int digit[][COL]) //判断这个最优的节点是否和目的节点一样{for (int i = 0; i < ROW; i++)for (int j = 0; j < COL; j++) {if (node_v[index].digit[i][j] != digit[i][j])return false;}return true;}ostream& operator<<(ostream& os, Node& node){for (int i = 0; i < ROW; i++) {文档Word.for (int j = 0; j < COL; j++)os << node.digit[i][j] << ' ';os << endl;}return os;}void PrintSteps(int index, vector<Node>& rstep_v)//输出每一个遍历的节点深度遍历{rstep_v.push_back(node_v[index]);index = node_v[index].index;while (index != 0){rstep_v.push_back(node_v[index]);index = node_v[index].index;}for (int i=rstep_v.size()-1;i>=0;i--)//输出每一步的探索过程cout << Step << rstep_v.size() - i<< endl << rstep_v[i] << endl;文档Word.}void Swap(int& a, int& b){int t;t = a;a = b;b = t;}void Assign(Node& node, int index){for (int i = 0; i < ROW; i++)for (int j = 0; j < COL; j++)node.digit[i][j] = node_v[index].digit[i][j];}int GetMinNode() //找到最小的节点的位置即最优节点{int dist = MAXNUM;int loc; // the location of minimize nodefor (int i = 0; i < node_v.size(); i++){文档Word.if (node_v[i].dist == MAXNUM)continue;else if ((node_v[i].dist + node_v[i].dep) < dist) { loc = i;dist = node_v[i].dist + node_v[i].dep;}}return loc;}bool isExpandable(Node& node){for(int i=0;i<node_v.size();i++) {if (isEqual(i, node.digit))return false;}return true;int Distance(Node& node, int digit[][COL]) {文档Word.int distance = 0;bool flag = false;for(int i = 0; i < ROW; i++)for (int j = 0; j < COL; j++)for (int k = 0; k < ROW; k++) {for (int l = 0; l < COL; l++) {if (node.digit[i][j] == digit[k][l]) {distance += abs(i - k) + abs(j - l);flag = true;break;}elseflag = false;}if(flag)break;return distance;}int MinDistance(int a,int b){文档Word.return (a<b?a:b);}void ProcessNode(int index){int x, y;bool flag;for (int i = 0; i < ROW; i++) {for (int j = 0; j < COL; j++) {if (node_v[index].digit[i][j] == 0) {x =i; y = j;flag = true;break;else flag = false;}if(flag)break;}Node node_up;文档Word.Assign(node_up, index);//向上扩展的节点int dist_up = MAXDISTANCE;if (x > 0){Swap(node_up.digit[x][y], node_up.digit[x - 1][y]);if (isExpandable(node_up)){dist_up = Distance(node_up, dest.digit);node_up.index = index;node_up.dist = dist_up;node_up.dep = node_v[index].dep + 1;node_v.push_back(node_up);}Node node_down;Assign(node_down, index);//向下扩展的节点int dist_down = MAXDISTANCE;if (x < 2){Swap(node_down.digit[x][y], node_down.digit[x + 1][y]); if (isExpandable(node_down))文档Word.{dist_down = Distance(node_down, dest.digit);node_down.index = index;node_down.dist = dist_down;node_down.dep = node_v[index].dep + 1;node_v.push_back(node_down);}}Node node_left;Assign(node_left, index);//向左扩展的节点int dist_left = MAXDISTANCE;if (y > 0){Swap(node_left.digit[x][y], node_left.digit[x][y - 1]); if (isExpandable(node_left)){dist_left = Distance(node_left, dest.digit);node_left.index = index;node_left.dist = dist_left;node_left.dep = node_v[index].dep + 1;文档Word.node_v.push_back(node_left);}}Node node_right;Assign(node_right, index);//向右扩展的节点int dist_right = MAXDISTANCE;if (y < 2){Swap(node_right.digit[x][y], node_right.digit[x][y + 1]); if (isExpandable(node_right)){dist_right = Distance(node_right, dest.digit);node_right.index = index;node_right.dist = dist_right;node_right.dep = node_v[index].dep + 1;node_v.push_back(node_right);}}node_v[index].dist = MAXNUM;}文档Word.int main() // 主函数{int number;cout << Input source: << endl;for (int i = 0; i < ROW; i++)//输入初始的表for (int j = 0; j < COL; j++) {cin >> number;src.digit[i][j] = number;}src.index = 0;src.dep = 1;cout << Input destination: << endl;//输入目的表for (int m = 0; m < ROW; m++)for (int n = 0; n < COL; n++) {cin >> number;dest.digit[m][n] = number;}文档Word.node_v.push_back(src);//在容器的尾部加一个数据cout << Search... << endl;clock_t start = clock();while (1){if (isEmptyOfOPEN()){cout << Cann't solve this statement! << endl;return -1;}else{int loc; // the location of the minimize node最优节点的位置loc = GetMinNode();if(isEqual(loc, dest.digit)){vector<Node> rstep_v;cout << Source: << endl;cout << src << endl;PrintSteps(loc, rstep_v);文档Word.cout << Successful! << endl;Cout <<Using <<(clock()-start)/CLOCKS_PER_SEC<< seconds. << endl;break;}elseProcessNode(loc); }}return 0;}文档Word。
八数码问题启发函数和代价函数

八数码问题启发函数和代价函数八数码问题作为经典的搜索问题,其解决过程中启发函数和代价函数的选择对搜索效率有着重要的影响。
本文将针对八数码问题中启发函数和代价函数的选择进行探讨,并分析它们在搜索过程中的作用和影响。
一、启发函数的选择启发函数是在搜索过程中用来评估节点的“接近程度”的函数,它可以指导搜索算法朝着离目标更近的方向前进,从而提高搜索效率。
在八数码问题中,常用的启发函数有误放置数目、曼哈顿距离和线性冲突等。
1. 误放置数目误放置数目是指当前状态与目标状态中不同数字的个数,它可以作为启发函数来评估当前状态与目标状态的“距离”。
当误放置数目越小,说明当前状态距离目标状态越近,因此误放置数目可以作为一种简单而有效的启发函数。
2. 曼哈顿距离曼哈顿距离是指当前状态的每个数字到目标状态的正确位置之间的曼哈顿距离之和。
曼哈顿距离可以更准确地评估当前状态与目标状态的“距离”,因此在某些情况下,比误放置数目更适合作为启发函数。
3. 线性冲突线性冲突是指在某一行或某一列中有两个数字的目的位置相互交叉,这种情况下移动其中一个数字就会导致另一个数字也需要移动。
线性冲突可以影响搜索的效率,因此考虑线性冲突可以使启发函数更精确地评估当前状态与目标状态的“距离”。
二、代价函数的选择代价函数是指在搜索过程中用来评估节点的“代价”的函数,它可以指导搜索算法在选择候选节点时进行排序,从而提高搜索效率。
在八数码问题中,常用的代价函数有实际代价和估计代价等。
1. 实际代价实际代价是指从初始状态到当前状态的实际代价,它可以作为代价函数来评估当前状态的“代价”。
通过记录从初始状态到当前状态的实际代价,搜索算法可以更准确地评估每个候选节点的“代价”,从而更有针对性地选择下一个节点。
2. 估计代价估计代价是指从当前状态到目标状态的估计代价,它可以作为代价函数来评估当前状态的“代价”。
估计代价通常是通过启发函数来估计的,因此选择合适的启发函数对于估计代价的准确性非常重要。
宽度优先搜索详解

宽度优先搜索详解宽度优先搜索(Breadth First Search, BFS)是一种用来遍历或搜索图形或树数据结构的算法。
该算法以广度为优先,从根节点开始,依次访问同层节点,直到遍历完整个图形或树。
本文将详细介绍宽度优先搜索的原理、应用场景以及实现方法。
一、原理解析宽度优先搜索主要基于队列数据结构实现,其具体流程如下:1. 将根节点(起始节点)放入队列中;2. 当队列不为空时,执行以下步骤:a. 取出队首元素进行访问;b. 将当前节点的所有相邻未访问过的节点加入队列;c. 标记当前节点为已访问;3. 重复步骤2,直到队列为空。
宽度优先搜索的核心思想是在同一层级的节点访问完之后才会继续访问下一层级的节点,确保了先广度后深度的遍历顺序。
二、应用场景宽度优先搜索在图形和树等数据结构中有广泛的应用。
以下是一些常见的应用场景:1. 最短路径问题:当图中每条边的权重相等时,宽度优先搜索可以用来求解起点到终点的最短路径。
2. 连通性问题:宽度优先搜索可以用来判断两个节点之间是否存在路径联通。
3. 键值搜索:对于带有层次结构的数据,如树结构或图像中的像素布局,宽度优先搜索可以帮助我们在最短时间内找到目标节点。
4. 社交网络分析:在社交网络中,宽度优先搜索可以用来寻找两个人之间的熟人关系链,或者寻找某个人的最近邻居。
5. 游戏路径搜索:在一些游戏中,如迷宫游戏或棋盘游戏,宽度优先搜索可以用来寻找到达目标位置的最短路径。
三、实现方法以下是宽度优先搜索的一种实现方法(以无向图为例):```pythonfrom collections import dequedef bfs(graph, start):visited = set() # 用于记录已访问的节点queue = deque([start]) # 使用双端队列作为辅助数据结构visited.add(start) # 将起始节点标记为已访问while queue:node = queue.popleft() # 取出队首节点print(node) # 访问节点的操作for neighbor in graph[node]: # 遍历当前节点的相邻节点if neighbor not in visited:queue.append(neighbor) # 将未访问过的节点加入队列visited.add(neighbor) # 标记为已访问```上述代码中,`graph`表示无向图的邻接表表示,`start`表示起始节点。
人工智能实验总结

总结
宽度优先搜索法
在有解的情形总能保证搜索到最短路经,也 就是移动最少步数的路径。但宽度优先搜索法的 最大问题在于搜索的结点数量太多,因为在宽度 优先搜索法中,每一个可能扩展出的结点都是搜 索的对象。随着结点在搜索树上的深度增大,搜 索的结点数会很快增长,并以指数形式扩张,从 而所需的存储空间和搜索花费的时间也会成倍增 长。
1 2
0 1 0 1
0 0 1 1
0 1 1 0
神经网络设计
用两层神经网络来实现,其中隐层为随机 感知器层(net1),神经网络元数目设计为 3,其权值和阈值是随机的,它的输出作为 输出层(分类层)的输入;输出层为感知 器层(net2),其神经元数为1,这里仅对 该层进行训练。
程序运行结果
随机感知器层的权值向量 iw1 = 0.4267 -0.6556 -0.5439 0.9376 -0.1007 -0.2886 随机感知器层的阈值向量 b1 = 0.4074 0.0441 0.8658
运行结果分析
上面实验结果可以看出,城市数目为30的 时候,当迭代次数为100,算法收敛慢,在 迭代次数内最优解没有达到稳定,没有搜 索到最好的解。 迭代次数为200和250的时候,算法基本达 到收敛,最优解在100代以后趋于稳定,表 明搜索到问题的最优解。
运行结果
当城市数目改变的时候: CityNum=50;最大代数gnmax=100;
程序运行结果
第二层感知器层的权值向量和阈值向量 iw2 = -3 -2 2 b2 = 2
“八”数码问题的宽度优先搜索与深度优先搜索

“八”数码问题的宽度优先搜索与深度优先搜索我在观看视频和查看大学课本及网上搜索等资料才对“八”数码问题有了更进一步的了解和认识。
一、“八”数码问题的宽度优先搜索步骤如下:1、判断初始节点是否为目标节点,若初始节点是目标节点则搜索过程结束;若不是则转到第2步;2、由初始节点向第1层扩展,得到3个节点:2、3、4;得到一个节点即判断该节点是否为目标节点,若是则搜索过程结束;若2、3、4节点均不是目标节点则转到第3步;3、从第1层的第1个节点向第2层扩展,得到节点5;从第1层的第2个节点向第2层扩展,得到3个节点:6、7、8;从第1层的第3个节点向第2层扩展得到节点9;得到一个节点即判断该节点是否为目标节点,若是则搜索过程结束;若6、7、8、9节点均不是目标节点则转到第4步;4、按照上述方法对下一层的节点进行扩展,搜索目标节点;直至搜索到目标节点为止。
二、“八”数码问题的深度优先搜索步骤如下:1、设置深度界限,假设为5;2、判断初始节点是否为目标节点,若初始节点是目标节点则搜索过程结束;若不是则转到第2步;3、由初始节点向第1层扩展,得到节点2,判断节点2是否为目标节点;若是则搜索过程结束;若不是,则将节点2向第2层扩展,得到节点3;4、判断节点3是否为目标节点,若是则搜索过程结束;若不是则将节点3向第3层扩展,得到节点4;5、判断节点4是否为目标节点,若是则搜索过程结束;若不是则将节点4向第4层扩展,得到节点5;6、判断节点5是否为目标节点,若是则搜索过程结束;若不是则结束此轮搜索,返回到第2层,将节点3向第3层扩展得到节点6;7、判断节点6是否为目标节点,若是则搜索过程结束;若不是则将节点6向第4层扩展,得到节点7;8、判断节点7是否为目标节点,若是则结束搜索过程;若不是则将节点6向第4层扩展得到节点8;9、依次类推,知道得到目标节点为止。
三、上述两种搜索策略的比较在宽度优先搜索过程中,扩展到第26个节点时找到了目标节点;而在深度优先搜索过程中,扩展到第18个节点时得到了目标节点。
“八”数码问题的宽度优先搜索与深度优先搜索

“八”数码问题的宽度优先搜索与深度优先搜索我在观看视频和查看大学课本及网上搜索等资料才对“八”数码问题有了更进一步的了解和认识。
一、“八”数码问题的宽度优先搜索步骤如下:1、判断初始节点是否为目标节点,若初始节点是目标节点则搜索过程结束;若不是则转到第2步;2、由初始节点向第1层扩展,得到3个节点:2、3、4;得到一个节点即判断该节点是否为目标节点,若是则搜索过程结束;若2、3、4节点均不是目标节点则转到第3步;3、从第1层的第1个节点向第2层扩展,得到节点5;从第1层的第2个节点向第2层扩展,得到3个节点:6、7、8;从第1层的第3个节点向第2层扩展得到节点9;得到一个节点即判断该节点是否为目标节点,若是则搜索过程结束;若6、7、8、9节点均不是目标节点则转到第4步;4、按照上述方法对下一层的节点进行扩展,搜索目标节点;直至搜索到目标节点为止。
二、“八”数码问题的深度优先搜索步骤如下:1、设置深度界限,假设为5;2、判断初始节点是否为目标节点,若初始节点是目标节点则搜索过程结束;若不是则转到第2步;3、由初始节点向第1层扩展,得到节点2,判断节点2是否为目标节点;若是则搜索过程结束;若不是,则将节点2向第2层扩展,得到节点3;4、判断节点3是否为目标节点,若是则搜索过程结束;若不是则将节点3向第3层扩展,得到节点4;5、判断节点4是否为目标节点,若是则搜索过程结束;若不是则将节点4向第4层扩展,得到节点5;6、判断节点5是否为目标节点,若是则搜索过程结束;若不是则结束此轮搜索,返回到第2层,将节点3向第3层扩展得到节点6;7、判断节点6是否为目标节点,若是则搜索过程结束;若不是则将节点6向第4层扩展,得到节点7;8、判断节点7是否为目标节点,若是则结束搜索过程;若不是则将节点6向第4层扩展得到节点8;9、依次类推,知道得到目标节点为止。
三、上述两种搜索策略的比较在宽度优先搜索过程中,扩展到第26个节点时找到了目标节点;而在深度优先搜索过程中,扩展到第18个节点时得到了目标节点。
宽度优先搜索(BFS)

宽度优先搜索(BFS)宽度优先搜索,⼜称为⼴度优先搜索,简称BFS搜索过程:从初始结点开始,逐层向下扩展,即第n层搜索未完成,不得进⼊下⼀层搜索⼀、初始结点⼊队,进⼊循环⼆、取出队列的第⼀个元素三、判断该结点是不是⽬标结点,如果是⽬标结点,则问题解决,跳出循环四、如果该结点不是⽬标结点,判断其是否能够扩展,若不能,跳到步骤⼆五、如果该结点能扩展,将其⼦结点放⼊队列的尾部六、跳到步骤⼆⽤⼀个经典的例⼦(⾛迷宫)来感受下给定⼀个⼆维数组 int a[10][10] = {0 , 1 , 0 , 0 , 0 0 , 1 , 0 , 1 , 0 0 , 0 , 0 , 0 , 0 0 , 1 , 1 , 1 , 0 0 , 0 , 0 , 1 , 0 } ;它表⽰⼀个迷宫,其中“1”代表墙,“0”代表通路,只能横着⾛或竖着⾛,要求编写程序找出从左上⾓到右下⾓的最短路径的长度#include<iostream>using namespace std ;int dx[] = {-1,0,1,0} ;int dy[] = {0,1,0,-1} ;int m , n ;int map[10][10] ;int visit[10][10] = {0} ;typedef struct Node {int x , y ;int step ;}Node;bool is_ok(Node cur) {if(cur.x < 0 || cur.x >= m || cur.y < 0 || cur.y >= n)return false ;return true ;}void bfs() {Node node[1000] ;int first , last ;first = last = 0 ;Node cur ;cur.x = 0 , cur.y = 0 ; cur.step = 0 ;node[last++] = cur ;visit[0][0] = 1 ;while(first < last) {cur = node[first++] ;if(cur.x == 4 && cur.y == 4) {cout << cur.step << endl ;break ;}for(int i = 0 ; i < 4 ; i++) {Node next ;next.x = cur.x + dx[i] ;next.y = cur.y + dy[i] ;if(map[next.x][next.y] == 1)continue ;if(visit[next.x][next.y] == 1)continue ;if(is_ok(next) == true) {next.step = cur.step + 1 ; visit[next.x][next.y] = 1 ; node[last++] = next ;}}}}int main() {cin >> m >> n ;for(int i = 0 ; i < m ; i++)for(int j = 0 ; j < n ; j++)cin >> map[i][j] ;bfs() ;return0 ;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*程序利用C++程序设计语言,在VC6.0下采用宽度优先的搜索方式,成功的解决了八数码问题。
程序中把OPEN表和CLOSED表用队列的方式存储,大大地提高了效率,开始的时候要输入目标状态和起始状态,由于在宽度优先搜索的情况下,搜索过程中所走过的状态是不确定且很庞大的,所以程序最后输出宽度优先情况下最少步数的搜索过程以及程序运行所需要的时间*/#include "iostream"#include "stdio.h"#include "stdlib.h"#include "time.h"#include "string.h"#include <queue>#include <stack>using namespace std;constint N = 3;//3*3图enum Direction{None,Up,Down,Left,Right};//方向staticint n=0;staticint c=0;struct Map//图{int cell[N][N];//数码数组Direction BelockDirec;//所屏蔽方向struct Map * Parent;//父节点};//打印图voidPrintMap(struct Map *map){cout<<"*************************************************"<<endl;for(int i=0;i<N;i++){for(int j=0;j<N;j++){cout<<map->cell[i][j]<<" ";}cout<<endl;}cout<<"*************************************************"<<endl;}//移动图struct Map * MoveMap(struct Map * map,DirectionDirect,boolCreateNewMap){struct Map * NewMap;//获取空闲格位置inti,j;for(i = 0; i < N; i++){ boolHasGetBlankCell = false; for(j = 0; j < N; j++){if(map->cell[i][j] == 0){ HasGetBlankCell = true; break;}}if(HasGetBlankCell) break;}//移动数字intt_i = i,t_j = j; boolAbleMove = true; switch(Direct){case Down:t_i++;if(t_i>= N)AbleMove=false;break;case Up:t_i--;if(t_i< 0)AbleMove=false;break;case Left:t_j--;if(t_j< 0)AbleMove=false;break;case Right:t_j++;if(t_j>= N)AbleMove=false;break;};if(!AbleMove)//不可以移动则返回原节点{return map;}if(CreateNewMap){NewMap = new Map();for(int x = 0; x < N; x++)for(int y = 0; y < N; y++)NewMap->cell[x][y] = map->cell[x][y];}elseNewMap = map;NewMap->cell[i][j] = NewMap->cell[t_i][t_j];NewMap->cell[t_i][t_j] = 0;returnNewMap;}boolIsSuccess(struct Map * map,struct Map * Target){boolIsSuc = true;for(int i = 0; i < N; i++){for(int j = 0; j < N; j++){if(map->cell[i][j] != Target->cell[i][j]){IsSuc = false;break;}}if(!IsSuc)break;}returnIsSuc;}struct Map * BNF_Search(struct Map * begin,struct Map * Target) {struct Map * p1, *p2, *p=NULL;boolIsSucc = false;queue<struct Map *> Queue;if(IsSuccess(begin,Target))return begin;Queue.push(begin);do{p1 = Queue.front();Queue.pop();for (int i = 1; i <= 4; i++){Direction Direct=(Direction)i;if(Direct == p1->BelockDirec)//跳过屏蔽方向continue;p2 = MoveMap(p1,Direct,true);if(p2 != p1) //数码是否可以移动{p2->Parent = p1;switch(Direct)//设置屏蔽方向,防止往回推{case Up:p2->BelockDirec = Down;break;case Down:p2->BelockDirec = Up;break;case Left:p2->BelockDirec = Right;break;case Right:p2->BelockDirec = Left;break;}if (IsSuccess(p2,Target)){p = p2;return p;}Queue.push(p2);n++;}}}while(!Queue.empty() || p == NULL);return p;}intJou(struct Map *map) //将八数码转换成一个数列,并计算其逆序数{int a=0;char b[9];for(int i=0;i<N;i++){for(int j=0;j<N;j++)b[i*3+j]=map->cell[i][j];}for(int k=0;k<9;k++){for(int h=0;h<k;h++){if((b[h]<b[k])&&b[h]!=0)a++;}}return a%2;}int main(){int a1,a2;inti,j,m,n;int target[9];int flag;Map Target;Map *begin,*T;begin=new Map;cout<<"请输入八数码的目标状态(用0代替空格):"<<endl;//输入目标状态for (i=0;i<9;i++) //此for循环用来把输入的数存入到target数组中{flag=0;cin>>target[i];for(j=0;j<i;j++)if(target[i]==target[j])flag=1;if (target[i]<0||target[i]>8||flag==1) //判断输入是否正确{i--;cout<<"输入错误,请关闭重新运行!\n";}}int k=0;for (m=0;m<3;m++) //把数组target中的数传给图Target {for (n=0;n<3;n++){Target.cell[m][n]=target[k];k++;}}//输入起始状态cout<<"请输入八数码的起始状态(用0代替空格):"<<endl;for (i=0;i<9;i++){flag=0;cin>>target[i];for(j=0;j<i;j++)if(target[i]==target[j]) //判断输入的数是否正确flag=1;if (target[i]<0||target[i]>8||flag==1){i--;cout<<"输入错误,请关闭重新运行!\n";}}k=0;for (m=0;m<3;m++){for (n=0;n<3;n++){begin->cell[m][n]=target[k];k++;}}begin->Parent = NULL;begin->BelockDirec = None;cout<<"目标图:"<<endl;PrintMap(&Target);cout<<"起始图:"<<endl;PrintMap(begin);a1=Jou(&Target);a2=Jou(begin);if(a1!=a2){cout<<"无解"<<endl;exit(0); //无解的话就退出,重新运行}else{double start=clock();cout<<"有解"<<endl;//图搜索T=BNF_Search(begin,&Target);//打印if(T != NULL){//把路径倒序Map *p=T;stack<Map *> Stack1;while(p->Parent != NULL){Stack1.push(p);p = p->Parent;}cout<<"宽度优先最少步数的搜索过程为:"<<endl;while(!Stack1.empty()){PrintMap(Stack1.top());c++;Stack1.pop();}cout<<"\n完成!"<<endl;cout<<"找到目标状态所需要的最少步数为:"<<c<<endl;double end=clock();cout<<"程序运行的时间为:"<<end-start<<"ms"<<endl;}}return 0;}。