15数码问题的解决算法算法和具体代码
- 格式:doc
- 大小:189.00 KB
- 文档页数:41
〈〈人工智能〉〉题目:15数码问题实验1:要求:采用广度优先算法解决15数码问题,输出扩展结点,步数和最终结果算法描述:广度优先搜索,即BFS(Breadth First Search),常常深度优先并列提及。
这是一种相当常用的图算法,其特点是:每次搜索指定点,并将其所有未访问过的近邻加入搜索队列(而深度优先搜索则是栈),循环搜索过程直到队列为空。
广度优先搜索算法的基本思想:从初始状态出发,按照给定的结点产生式规则(算符、结点扩展规则)生产第一层结点,每生成一个结点就检查是不是目标结点,如果是目标结点就搜索结束,如果不是目标结点并且前面没出现过就保存该结点(入队列);再用产生式规则将所有第一层的结点依次扩展,得到第二层结点,同时检查是否为目标结点,是目标搜索停止,不是并且没出现过保存(入队);再把第二层的结点按产生规则扩展生产第三层结点,直至找到目标或所有的状态找完但找不到目标(队列空)。
特点:先生成深度为1的所有结点,再生产深度为2的所有结点,依次类推。
先横向,再纵向。
这种方法找到目标,需要的步数一定最少。
程序算法流程图:描述:(1).把起始结点放到OPEN表中。
(2).如果OPEN表是个空表,则没有解,失败退出;否则继续。
(3).把第一个结点从OPEN表中移出,并把它放入CLOSE表的扩展节点表中。
(4).扩展结点N。
如果没有后继结点,则转向步骤(2)。
(5).把N的所有后继结点放到OPEN表的末端,并提供从这些后继结点回到N的指针。
(6).如果N的任意个后继结点是个目标结点,则找到一个解答,成功退出;否则转向步骤(2).流程图:输入:初始态int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};目标状态:int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};输出截图:由于输出的路径节点很多这里只是显示最终结果和步数。
1.一个SSE寄存器可容纳____个短整型数。
A 2B 4C 8D 16我的答案:C2.采用划分子矩阵技术优化矩阵乘法CUDA程序,子矩阵数组变量声明应加___前缀。
A __global__B __device___C __shared__D __private__我的答案:C3.起泡排序改为奇偶转置排序,消除了循环步间的数据依赖的原因是____。
A 增大了元素比较距离B 减小了元素比较距离C 改为元素两两分组比较D 消除了元素比较我的答案:C4.求解同一个问题的4个并行算法的等效率函数分析结果如下,其中____的可扩展性最优。
A Θ(plogp)B Θ(p^2)C Θ(p^2logp)D Θ(p^3)我的答案:A5.为防止编译器不支持OpenMP,应使用____实现OpenMP代码和普通代码的条件编译。
A "#include "B "#pragma omp parallel"C "#ifdef _OPENMP"D "#define _OPENMP"我的答案:C6.利用cache line一次读取多个数据字的机制优化程序访存性能,其机理是____。
A 降低了访存延迟B 隐藏了访存延迟C 利用了cache空间局部性D 利用了cache时间局部性我的答案:C7.有大量分支指令的程序不适合下面哪种体系结构上进行并行化?A SISDB SIMDC SPMDD MIMD我的答案:B8.CPU cache大小为32KB,如希望(单精度浮点数)矩阵乘法计算过程中所有数据都驻留cache中,则矩阵大小最大为A 16*16B 32*32C 64*64D 128*128我的答案:C9.pthread_join的第二个参数的作用是____。
A 设置指定线程属性B 获取指定线程属性C 向指定线程传递参数D 获取指定线程函数返回结果我的答案:D10.在分布式内存架构编程中,进程间不能____。
15数码问题解法The 15-puzzle is a classic sliding puzzle that consists of 15 numbered tiles on a 4x4 grid with one empty space. The goal is to arrange the tiles in numerical order by sliding them into the empty space. It might seem like a simple task, but the puzzle can be quite challenging and require strategic thinking to solve.15数码问题是经典的滑动拼图,由4x4网格上的15个编号瓦片和一个空格组成。
目标是通过将瓦片滑入空格来按数字顺序排列瓦片。
这个谜题看起来可能很简单,但是解决这个问题可能会很有挑战性,需要策略性的思维来解决。
One approach to solving the 15-puzzle involves creating a solving strategy that prioritizes certain moves over others. By identifying patterns and common sequences of moves, you can improve your efficiency in solving the puzzle. This can help you avoid getting stuck in dead-end positions and find the most efficient path to completing the puzzle.解决15数码问题的一种方法是创建一个解决策略,优先考虑某些移动而不是其他移动。
目录1 实验概述 (2)2 十五数码问题分析 (2)2.1十五数码问题简介 (2)2.2可行性分析 (3)3问题的求解策略 (3)3.1算法分析 (3)3.2 A*算法设计 (4)4 实验总结 (5)4.1 实验可视化界面 (5)4.2个人体会 (7)4.3 详细代码: 71 实验概述十五数码问题来源于美国的科学魔术大师萨姆.洛伊德(Sam I.oyd)在1978年推出的著名的“14-15”智力玩具。
这个游戏曾经风靡欧美大陆" 。
洛伊德的发明其实只是将重排九宫(即八数码问题)中的3阶方阵扩大到4 阶方阵罢了。
由于这个细微的变化, 十五数码问题的规模远远大于八数码问题, 八数码问题的规模较小, 总的状态数为9!(=362880)个, 而十五数码问题的状态,数为16!()个。
故十五数码问题更能评价一个算法的“智能”水平。
2 十五数码问题分析2.1十五数码问题简介15数码问题又叫移棋盘问题, 是人工智能中的一个经典问题。
所谓的15数码问题: 就是在一个4×4的16宫格棋盘上, 摆放有15个将牌, 每一个将牌都刻有1~15中的某一个数码。
棋盘中留有一个空格, 允许其周围的某一个将牌向空格移动, 这样通过移动将牌就可以不断改变将牌的布局。
这种求解的问题是: 给定一种初始的将牌布局或结构(称初始状态)和一个目标布局(称目标状态), 问如何移动数码, 实现从初始状态到目标状态的转变, 如下图所示。
问题的实质就是寻找一个合法的动作序列2.2可行性分析十五数码问题存在无解的情况,当遍历完所有可扩展的状态也没有搜索到目标状态就判断为无解。
可以根据状态的逆序数来先验的判断是否有解,当初始状态的逆序数和目标状态的逆序数的奇偶性相同时,问题有解;否则问题无解。
状态的逆序数是定义如下: 把四行数展开排成一行,并且丢弃数字0 不计入其中,ηi是第i 个数之前比该数小的数字的个数,则η=Σηi 是该状态的逆序数,例如: 对于初始状态: 5.1.2.4.9、 6.3.8、13.15.10、11.14.7、12.其η=0+0+1+2+4+4+2+6+8+9+8+9+11+6+11=81;对于目标状态: 1.2.3.4.5.6.7、8、9、10、11.12.13.14.15, 其η=0+1+2+3+4+5+6+7+8+9+10+11+12+13+14=105。
《人工智能及其应用》实验指导书浙江工业大学计算机科学与技术学院—人工智能课程组2011年9月前言本实验是为了配合《人工智能及其应用》课程的理论学习而专门设置的。
本实验的目的是巩固和加强人工智能的基本原理和方法,并为今后进一步学习更高级课程和信息智能化技术的研究与系统开发奠定良好的基础。
全书共分为八个实验:1.产生式系统实验;2.模糊推理系统实验;3.A*算法求解8数码问题实验;4.A*算法求解迷宫问题实验;5.遗传算法求解函数最值问题实验;6.遗传算法求解TSP问题实验;7.基于神经网络的模式识别实验;8.基于神经网络的优化计算实验。
每个实验包括有:实验目的、实验内容、实验条件、实验要求、实验步骤和实验报告等六个项目。
本实验指导书包括两个部分。
第一个部分是介绍实验的教学大纲;第二部分是介绍八个实验的内容。
由于编者水平有限,本实验指导书的错误和不足在所难免,欢迎批评指正。
人工智能课程组2011年9月目录实验教学大纲 (1)实验一产生式系统实验 (3)实验二模糊推理系统实验 (5)实验三A*算法实验I (9)实验四A*算法实验II (12)实验五遗传算法实验I (14)实验六遗传算法实验II (18)实验七基于神经网络的模式识别实验 (20)实验八基于神经网络的优化计算实验 (24)实验教学大纲一、学时:16学时,一般安排在第9周至第16周。
二、主要仪器设备及运行环境:PC机、Visual C++ 6.0、Matlab 7.0。
三、实验项目及教学安排序号实验名称实验平台实验内容学时类型教学要求1 产生式系统应用VC++ 设计知识库,实现系统识别或分类等。
2 设计课内2 模糊推理系统应用Matlab 1)设计洗衣机的模糊控制器;2)设计两车追赶的模糊控制器。
2 验证课内3 A*算法应用I VC++ 设计与实现求解N数码问题的A*算法。
2 综合课内4 A*算法应用II VC++ 设计与实现求解迷宫问题的A*算法。
精心整理一、15数码问题的描述及其状态空间法表示(1)15数码问题描述15数码问题又叫移棋盘问题,是人工智能中的一个经典问题。
所谓的15数码问题:就是在一个4×4的16宫格棋盘上,摆放有15个将牌,每一个将牌都刻有1~15中的某一个数码。
棋盘中留有一个空格,允许其周围的某一个将牌向空格移动,这样通过移动将牌就可以不断改变将牌的布局。
这种求解的问题是:给定一种初始的将牌布局或结构(称初始状态)和一个目标布局(称目标状态),问如何移动数码,实现从初始状态到目标状态的转变,如图1所示。
问题的实质就是寻找一个合法的目标状态集合。
十五数码的状态空间法:初始状态S[4][4]={5,12,11,4,13,6,3,10,14,2,7,9,1,15,0,8};(0表示空格)目标状态G[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};操作符集合F={空格上移,空格下移,空格左移,空格右移}状态空间的一个解:是一个有限的操作算子序列,它使初始状态转化为目标状态:S0-f1->S1-f2->...fk->G。
二、A*算法的基本原理、算法步骤、流程图(1)A*算法基本原理A*算法是一种有序搜索算法,其特点在于对评价函数的定义上。
对于一般的有序搜索,总是选择f值最小的节点作为扩展节点。
因此,f是根据需要找到一条最小代价路径的观点来估算节点的,可考虑将每个节点n的估价函数值分解为两个分量:从起始节点到节点n的最小代价路径的代价与从节点n到目标节点的最小代价路径的代价之和,也就是说f(n)是约束通过节点n的一条最小代价路径的代价的一个估计。
再定义一个函数f*,使得在任意一个节点n上的函数值f*(n)就是从节点S到节点n的一条最佳路径的实际代价加上从节点n到目标节点的一条最佳路径的代价之和,即:***在第7步中,如果搜索过程发现一条路径到达一个节点的代价比现存的路径代价低,就要重定向指向该节点的指针。
利用状态空间法解决十五数码游戏问题学号19110227 姓名季佳辉完成时间2013年11 月1.十五数码游戏简介十五数码游戏问题是在4*4方格盘上,放有15个数码,剩下第16个为空,每一空格其上下左右的数码可移至空格。
问题给定初始位置和目标位置,要求通过一系列的数码移动,将初始位置转化为目标位置。
2.十五数码游戏问题的状态空间法表示问题的状态空间是指表示问题可能态及关系图,记作三元态(S,F,G)。
它含三个集合:初始态集S;操作符集F;目标态集G。
十五数码问题状态空间法:初始态S[4][4]={5,1,2,4,9,6,3,8,13,10,7,11,0,14,15,12}。
目标态G[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0}(0表示空格)。
操作符集F=[空格左移、上移、右移、下移],实现状态转换。
3.十五数码游戏问题的盲目搜索技术1. 宽度优先搜索如果搜索是以接近起始节点的程度依次扩展节点的,那么这种搜索就叫做宽度优先搜索。
这种搜索是逐层进行的;在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点。
其搜索过程如图(1)所示。
图1 宽度优先搜索示意图宽度优先搜索算法如下:(1)把起始节点放到OPEN 表中(如果该起始节点为一目标节点,则得到解) (2)如果OPEN 是个空表,则无解,失败退出;否则继续下一步(3)把第一个节点(记作节点n )从OPEN 表移出,并把它放入CLOSED 的已扩展节点表中(4)扩展节点n 。
如果没有后继节点,则转向第(2)步(5)把n 的所有后继节点放到OPEN表的末端,并提供从这些后继节点回到n 的指针(6)如果n 的任一个后继节点是个目标节点,则找到一个解(反向追踪得到从目标节点到起始节点的路径),成功退出,否则转向第(2)步其流程图如图2所示图2 宽度优先算法流程图2、深度优先搜索在深度优先搜索中,首先扩展最新产生的(即最深的)节点。
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表中的结点按从小到大排序。
一、15数码问题的描述及其状态空间法表示(1)15数码问题描述15数码问题又叫移棋盘问题,是人工智能中的一个经典问题。
所谓的15数码问题:就是在一个4×4的16宫格棋盘上,摆放有15个将牌,每一个将牌都刻有1~15中的某一个数码。
棋盘中留有一个空格,允许其周围的某一个将牌向空格移动,这样通过移动将牌就可以不断改变将牌的布局。
这种求解的问题是:给定一种初始的将牌布局或结构(称初始状态)和一个目标布局(称目标状态),问如何移动数码,实现从初始状态到目标状态的转变,如图1所示。
问题的实质就是寻找一个合法的动作序列(a)初始状态(b)目标状态图1 15数码问题的一个实例(2)状态空间法表示人工智能问题的求解是以知识表示为基础的。
如何将已获得的有关知识以计算机内部代码形式加以合理地描述、存储、有效地利用便是表示应解决的问题[1]。
目前的知识表示方法有十余种,如:一阶谓词逻辑表示法、产生式表示法、状态空间表示法、语义网格表示法、框架表示法、脚本表示法、面向对象表示法等。
任何一个给定的问题可能存在多种知识表示方法,人们可以根据待求解问题的领域知识选择适当的知识表示方法。
这里我们只强调状态空间表示法。
把求解的问题表示成问题状态、操作、约束、初始状态和目标状态。
状态空间就是所有可能的状态的集合。
求解一个问题就是从初始状态出发,不断应用可应用的操作,在满足约束的条件下达到目标状态。
问题求解过程就可以看成是问题状态在状态空间的移动。
状态是为描述某类不同事物间的差别而引入的一组最少变量q0,q1,…,q n的有序集合。
问题的状态空间是一个表示该问题全部可能状态及其关系的图。
记为三元状态(S、F、G),其中S所有可能的问题初始状态集合,F操作符集合,G目标状态集合。
十五数码的状态空间法:初始状态S[4][4]={5,12,11,4,13,6,3,10,14,2,7,9,1,15,0,8};(0表示空格)目标状态G[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};操作符集合F={空格上移,空格下移,空格左移,空格右移}状态空间的一个解:是一个有限的操作算子序列,它使初始状态转化为目标状态:S0-f1->S1-f2->...f k->G。
〈〈人工智能〉〉题目:15数码问题实验1:要求:采用广度优先算法解决15数码问题,输出扩展结点,步数和最终结果算法描述:广度优先搜索,即BFS(Breadth First Search),常常深度优先并列提及。
这是一种相当常用的图算法,其特点是:每次搜索指定点,并将其所有未访问过的近邻加入搜索队列(而深度优先搜索则是栈),循环搜索过程直到队列为空。
广度优先搜索算法的基本思想:从初始状态出发,按照给定的结点产生式规则(算符、结点扩展规则)生产第一层结点,每生成一个结点就检查是不是目标结点,如果是目标结点就搜索结束,如果不是目标结点并且前面没出现过就保存该结点(入队列);再用产生式规则将所有第一层的结点依次扩展,得到第二层结点,同时检查是否为目标结点,是目标搜索停止,不是并且没出现过保存(入队);再把第二层的结点按产生规则扩展生产第三层结点,直至找到目标或所有的状态找完但找不到目标(队列空)。
特点:先生成深度为1的所有结点,再生产深度为2的所有结点,依次类推。
先横向,再纵向。
这种方法找到目标,需要的步数一定最少。
程序算法流程图:描述:(1).把起始结点放到OPEN表中。
(2).如果OPEN表是个空表,则没有解,失败退出;否则继续。
(3).把第一个结点从OPEN表中移出,并把它放入CLOSE表的扩展节点表中。
(4).扩展结点N。
如果没有后继结点,则转向步骤(2)。
(5).把N的所有后继结点放到OPEN表的末端,并提供从这些后继结点回到N的指针。
(6).如果N的任意个后继结点是个目标结点,则找到一个解答,成功退出;否则转向步骤(2).流程图:输入:初始态int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};目标状态:int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};输出截图:由于输出的路径节点很多这里只是显示最终结果和步数。
〈〈人工智能〉〉题目:15数码问题实验1:要求:采用广度优先算法解决15数码问题,输出扩展结点,步数和最终结果算法描述:广度优先搜索,即BFS(Breadth First Search),常常深度优先并列提及。
这是一种相当常用的图算法,其特点是:每次搜索指定点,并将其所有未访问过的近邻加入搜索队列(而深度优先搜索则是栈),循环搜索过程直到队列为空。
广度优先搜索算法的基本思想:从初始状态出发,按照给定的结点产生式规则(算符、结点扩展规则)生产第一层结点,每生成一个结点就检查是不是目标结点,如果是目标结点就搜索结束,如果不是目标结点并且前面没出现过就保存该结点(入队列);再用产生式规则将所有第一层的结点依次扩展,得到第二层结点,同时检查是否为目标结点,是目标搜索停止,不是并且没出现过保存(入队);再把第二层的结点按产生规则扩展生产第三层结点,直至找到目标或所有的状态找完但找不到目标(队列空)。
特点:先生成深度为1的所有结点,再生产深度为2的所有结点,依次类推。
先横向,再纵向。
这种方法找到目标,需要的步数一定最少。
程序算法流程图:描述:(1).把起始结点放到OPEN表中。
(2).如果OPEN表是个空表,则没有解,失败退出;否则继续。
(3).把第一个结点从OPEN表中移出,并把它放入CLOSE表的扩展节点表中。
(4).扩展结点N。
如果没有后继结点,则转向步骤(2)。
(5).把N的所有后继结点放到OPEN表的末端,并提供从这些后继结点回到N的指针。
(6).如果N的任意个后继结点是个目标结点,则找到一个解答,成功退出;否则转向步骤(2).流程图:输入:初始态int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};目标状态:int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};输出截图:由于输出的路径节点很多这里只是显示最终结果和步数。
數字的問題解決策略掌握解決數字問題的策略和方法数字的问题解决策略:掌握解决数字问题的策略和方法在日常生活和学习中,我们经常会遇到各种各样与数字相关的问题。
无论是计算、统计、推理还是分析,解决数字问题需要一定的策略和方法。
本文将介绍一些常用的数字问题解决策略,帮助读者更好地应对各类数字问题。
一、整体与局部解决数字问题时,首先要理清整体与局部的关系。
有时,一个问题给出的数字和条件较为复杂,此时我们可以通过分解整体和关注局部来解决问题。
例如,求一个数的平方根时,可以先逼近整个数的范围,再对局部进行逼近;又如,统计一个班级的成绩时,可以先统计每个学生的成绩,再整合到整体。
二、抽象与实际数字问题往往需要将抽象的概念和实际情况相结合。
通过将问题中的数字进行抽象,可以更好地理解问题的本质,并找到解决问题的方法。
例如,一个经典的应用是带入具体数值进行计算,通过不同数值的验证来确定答案的准确性。
此外,可以将数字与图形、图表等形式相结合,以更直观的方式解决数字问题。
三、等式与不等式在解决一些带有约束条件的数字问题时,等式和不等式常常是解题的基本工具。
建立合适的等式或不等式方程,可以将问题转化为容易求解的形式。
例如,有关长度和宽度的关系问题可以通过建立等式或不等式来求解,使问题更具可操作性,进而得到解题思路。
四、归纳与递推归纳与递推是解决数字问题的重要方法之一。
当问题中的数字规律不明显或难以解析时,我们可以通过寻找其中的规律,进而把握住问题的关键。
例如,求解一个数列的第n项,可以通过找到数列的通项公式,从而递推得到结果。
五、试错与验证解决数字问题时,试错与验证也是常用的策略之一。
我们可以选择一些合适的数字进行尝试,验证求解的过程与结果是否符合要求。
这样,可以在不确定的情况下逐步逼近准确答案,提高解题的准确性。
尤其是在较为复杂的问题中,试错与验证可以避免中途出错并及时纠正。
六、与他人交流数字问题解决的策略与方法可以与他人进行交流和分享。
数码迷题求解算法的比较及A*算法的简单介绍摘要:数码谜题源于一古老的智力游戏,是人工智能领域中的经典问题。
本文着眼于8数码问题求解的具体实现。
分析了数码迷题求解的搜索策略。
对三种搜索算法进行了比较权衡,并对经典启发式搜索算法a*算法进行了简单介绍,介绍了该算法框架下的启发函数及open表结构。
关键词:数码迷题;启发式搜索;a*算法;定理化判断中图分类号:o14 文献标识码:a 文章编号:1009-0118(2011)-03-0018-01一、引言8数码迷题又称重排九宫,问题描述如下:用数字1~8标注的棋子摆放在一个3×3共9个格子的棋盘上,空出一个格子使棋子能在盘内水平滑动,8个符号在棋盘上的排列称为8数码的状态,游戏要求给定一个初始的状态和一个终止状态,且每次只能移动一个棋子,求从任一初始棋局变化到另一目标棋局是否有解,以及有解时的解法。
二、定理化判定可解性按从左往右,从上到下的顺序将棋局状态表示为一个数列p=a1a2a3a4a5a6a7a8,ai为1,2…8八个数码中的一个,p是1,2…8的一个排列,称p是该棋局的状态数列。
在序列p中对iaj,则称aj出现了一个逆序,元素aj的逆序数记为r(aj)。
于是序列p 的逆序数记为r(p),定义为除元素0外所有元素的逆序个数之和。
序列p的元素存放在数组s[1∽n×n]中。
三、搜索算法的分析比较(一)三种搜索算法的数据结构分析。
首先简单介绍下open表和closed的动态数据结构,前者记录当前未考察的结点,后者记录考察过的结点。
扩展所得子结点按其估值的大小插入open表中合适的位置,每次从中选出估值最小的加以扩展。
每个结点都保留父结点的信息,这保证了搜索完毕后,能通过closed表返回完整的搜索路径。
一般图的搜索算法中,提高效率的关键在于open表中结点的排列方式,若每次排在表首的结点都最终搜索到解的路径上,则算法不需扩展任何多余的结点就可快速结束搜索。
A*算法实验I-十五数码班级:计自1202班学号:201226100531 姓名:赵玮瑄一、实验目的在八数码的基础上写出十五数码的问题,熟悉掌握A*算法的运算过程。
进一步理解求解过程和求解次序。
二、实验原路A*算法是一种启发式图搜索算法,其特点在于对估价函数的定义上。
对于一般的启发式图搜索,总是选择估价函数f值最小的节点作为扩展节点。
因此,f是根据需要找到一条最小代价路径的观点来估算节点的,所以,可考虑每个节点n的估价函数值为两个分量:从起始节点到节点n的实际代价g(n)以及从节点n到达目标节点的估价代价h(n),且)h ,)(*nh为n节点到目的结点的最优路径的代n)(*(nh价。
十六数码问题是在4×4的十六宫格棋盘上,摆有16个刻有1~F数码的将牌。
棋盘中有一个空格,允许紧邻空格的某一将牌可以移到空格中,这样通过平移将牌可以将某一将牌布局变换为另一布局。
针对给定的一种初始布局或结构(目标状态),问如何移动将牌,实现从初始状态到目标状态的转变。
三、实验结果三种估价函数:源代码:int calw(string s)//计算该状态的不在位数h(n){int re=0;for(int i=0;i<16;i++) if(s[i]!=t[i] && s[i]!='0') re++;return re;}int calw1(string s)//自定义估价函数,是各数码移到目的位置所需移动的距离的总和{int re=0;for(int i=0;i<9;i++){ i f(s[i]!=t[i] && s[i]!='0'){ for(int j=0;j<9;j++){if(s[i]==t[j]) break;}re+=abs(i/3-j/3)+abs(i%3-j%3);}}return re;}int calw2(string s)//宽度优先搜索算法(即令估计代价h(n)=0的A*算法){return 0;}表1 不同启发函数h(n)求解十五数码问题的结果比较四、实验总结总的来说,十五数码的基本运算过程与八数码是相同的,基本的运算机理也是差不多的,运算的方法也基本一致,但是运算量却比八数码的运算量大很多。
〈〈人工智能〉〉题目:15数码问题实验1:要求:采用广度优先算法解决15数码问题,输出扩展结点,步数和最终结果算法描述:广度优先搜索,即BFS(Breadth First Search),常常深度优先并列提及。
这是一种相当常用的图算法,其特点是:每次搜索指定点,并将其所有未访问过的近邻加入搜索队列(而深度优先搜索则是栈),循环搜索过程直到队列为空。
广度优先搜索算法的基本思想:从初始状态出发,按照给定的结点产生式规则(算符、结点扩展规则)生产第一层结点,每生成一个结点就检查是不是目标结点,如果是目标结点就搜索结束,如果不是目标结点并且前面没出现过就保存该结点(入队列);再用产生式规则将所有第一层的结点依次扩展,得到第二层结点,同时检查是否为目标结点,是目标搜索停止,不是并且没出现过保存(入队);再把第二层的结点按产生规则扩展生产第三层结点,直至找到目标或所有的状态找完但找不到目标(队列空)。
特点:先生成深度为1的所有结点,再生产深度为2的所有结点,依次类推。
先横向,再纵向。
这种方法找到目标,需要的步数一定最少。
程序算法流程图:描述:(1).把起始结点放到OPEN表中。
(2).如果OPEN表是个空表,则没有解,失败退出;否则继续。
(3).把第一个结点从OPEN表中移出,并把它放入CLOSE表的扩展节点表中。
(4).扩展结点N。
如果没有后继结点,则转向步骤(2)。
(5).把N的所有后继结点放到OPEN表的末端,并提供从这些后继结点回到N的指针。
(6).如果N的任意个后继结点是个目标结点,则找到一个解答,成功退出;否则转向步骤(2).流程图:输入:初始态int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};目标状态:int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};输出截图:由于输出的路径节点很多这里只是显示最终结果和步数。
实验2:要求:采用深度优先算法实现15数码问题。
算法描述:设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y)。
若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过;然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边。
上述过程直至从x出发的所有边都已检测过为止。
此时,若x不是源点,则回溯到在x之前被访问过的顶点;否则图中所有和源点有路径相通的顶点(即从源点可达的所有顶点)都已被访问过,若图G是连通图,则遍历过程结束,否则继续选择一个尚未被访问的顶点作为新源点,进行新的搜索过程。
流程图:描述:(1).把起始结点放到OPEN表中。
如果此结点为一目标结点,则得到一个解。
(2).如果OPEN表是个空表,则没有解,失败退出;否则继续。
(3).把第一个结点从OPEN表中移出,并把它放入CLOSE表中。
(4).如果结点N的深度等于最大深度,则转向步骤(2)。
(5).扩展结点N,产生其全部后裔,并把它们放入OPEN表的前头。
如果没有后裔,则转向步骤(2)。
(6).如果N的任意个后继结点是个目标结点,则找到一个解答,成功退出;否则转向步骤(2).流程图:输入:初始态int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};目标状态:int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};输出截图:由于输出的路径节点很多这里只是显示最终结果和步数实验3:要求:采用启发式的A星算法实现15数码问题。
算法描述:启发式搜索算法A,一般简称为A算法,是一种典型的启发式搜索算法。
其基本思想是:定义一个评价函数f,对当前的搜索状态进行评估,找出一个最有希望的节点来扩展。
评价函数的形式如下:f(n)=g(n)+h(n)其中n是被评价的节点。
f(n)、g(n)和h(n)各自表述什么含义呢?我们先来定义下面几个函数的含义,它们与f(n)、g(n)和h(n)的差别是都带有一个"*"号。
g*(n):表示从初始节点s到节点n的最短路径的耗散值;h*(n):表示从节点n到目标节点g的最短路径的耗散值;f*(n)=g*(n)+h*(n):表示从初始节点s经过节点n到目标节点g的最短路径的耗散值。
而f(n)、g(n)和h(n)则分别表示是对f*(n)、g*(n)和h*(n)三个函数值的的估计值。
是一种预测。
A算法就是利用这种预测,来达到有效搜索的目的的。
它每次按照f(n)值的大小对OPEN表中的元素进行排序,f值小的节点放在前面,而f值大的节点则被放在OPEN表的后面,这样每次扩展节点时,都是选择当前f值最小的节点来优先扩展。
流程图:描述:(1).把起始结点放到OPEN表中。
计算F(S),并把其值与结点S联系起来。
(2).如果OPEN表是个空表,则没有解,失败退出;否则继续。
(3).从OPEN表中选择一个F值最小的结点I。
如果有几个结点合格,当其中有一个为目标结点时,则选择此目标结点,否则就选择其中任一个结点为结点I。
(4).把结点I从OPEN表中移出,并把它放入CLOSE的扩展结点表中。
(5).如果I是目标结点,则成功退出,求得一个解。
(6).扩展结点I,生成其全部后继结点。
对于I的每一个后继结点J:(a).计算F(J).(b).如果J既不再OPEN表中,也不再CLOSE表中,则用估价函数F把它添入OPEN表中。
从J加一指向其父辈结点I的指针,以便一旦找到目标结点时记住一个解答捷径。
(c).如果J已在OPEN表或CLOSE表上,则比较刚刚对J计算过的F值和前面计算过的该结点在表中的F值。
如果新的F值较小,则(i).以此新值代替旧值。
(ii).从J指向I,而不是指向它的父辈结点。
(iii).如果结点J在CLOSE表中,则把它移回OPEN表中。
(7).转向(2),即GOTO(2)流程图:输入:初始态int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};目标状态:int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};输出截图:6走完成,逆序输出。
各源代码见附件。
附件:(源程序代码)1 广度优先算法:#include <stdlib.h>#include <string.h>#include <stdio.h>#include<iostream.h>#define N 4typedef struct QNode{int data[N][N];int ancent; //标记方向左上下右分别为1234 5为可以任意方向int x;int y;struct QNode *next;struct QNode *prior;}QNode, *QueuePtr;typedef struct{QueuePtr head;QueuePtr rear;}LinkQueue;int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};int n=0;//记录步数int x,y;bool check(){//判断是否有路径,根据初始态和目标态的秩序,若不同为奇数或同为偶数,则无路径int temp=A[x][y];int i,j,sum2 = 0,sum1 = 0;int a[N*N],b[N*N];for(i=0;i<N;i++){for(j=0;j<N;j++){a[i*N+j]=A[i][j];}}for(i=0;i<N;i++){for(j=0;j<N;j++){b[i*N+j]=B[i][j];}}for(i=0;i<N*N-1;i++){for(j=i+1;j<N*N;j++){if(a[i]!=temp&&a[j]!=temp&&a[i]>a[j]) sum1++;}}for(i=0;i<N*N-1;i++){for(j=i+1;j<N*N;j++){if(b[i]!=temp&&b[j]!=temp&&b[i]>b[j]) sum2++;}}if((sum1%2==0&&sum2%2==1)||(sum1%2==1&&sum2%2==0)){ return false;}return true;}bool begin_opint(){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(A[i][j]==0){x=i;y=j;return true;}}}return false;}bool compare(int a[N][N]){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(a[i][j]!=B[i][j])return false;}}return true;}bool moveleft(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(y==0)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x][y-1];(*b)->data[x][y-1]=k;(*b)->x=x;(*b)->y=y-1;return true;}bool moveup(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(x==0)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x-1][y];(*b)->data[x-1][y]=k;(*b)->x=x-1;(*b)->y=y;return true;}bool movedown(int a[N][N],QueuePtr *b,int x,int y){int k,i,j;if(x==N-1)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x+1][y];(*b)->data[x+1][y]=k;(*b)->x=x+1;(*b)->y=y;return true;}bool moveright(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(y==N-1)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x][y+1];(*b)->data[x][y+1]=k;(*b)->x=x;(*b)->y=y+1;return true;}bool copy(QueuePtr *a){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++)(*a)->data[i][j]=A[i][j];}return true;}void output(int a[N][N]){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){printf(" %d",a[i][j]);}printf("\n");}printf("\n");}void main(){QueuePtr closed,p,q;LinkQueue open;/*if(!check()){printf("no answer!!\n"); //no answerexit(0);}*/if(!begin_opint()){printf("no 0 opint!!\n"); //确定0点exit(0);}open.head=open.rear=(QueuePtr)malloc(sizeof(QNode));//头结点open.rear->next=open.head->next=NULL;open.head->prior=open.head->prior=NULL;closed=(QueuePtr)malloc(sizeof(QNode));//头结点closed->next=NULL;closed->prior=NULL;p=(QueuePtr)malloc(sizeof(QNode));//S0进open表copy(&p);p->x=x;p->y=y;p->ancent=5;p->prior=NULL;p->next=open.head->next;open.head->next=p;open.rear=open.head; //open表的尾结点暂时设置为头结点while(open.head->next!=NULL){q=open.head->next; //open进closedopen.head->next=q->next; //移除open表头结点q->next=closed->next; //插入closed表的表头closed->next=q;n++;output(q->data);if(compare(q->data)){printf("ok!\n");printf("steps is %d\n",n);break;}//将后继结点放入open表中switch(closed->next->ancent){case 1: p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从右来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=1;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=2;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=3;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);break;case 2:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从下来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=1;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=2;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=4;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);break;case 3:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从上来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=1;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=3;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=4;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);break;case 4:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从左边来if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=2;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=3;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=4;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);break;default:p=(QueuePtr)malloc(sizeof(QNode));//初始情况if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=1;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=2;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=3;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->prior=closed->next;p->ancent=4;p->next=open.rear->next;open.rear->next=p;open.rear=p;}else free(p);break;}}}2 深度优先算法:#include <stdlib.h>#include <string.h>#include <stdio.h>#include<iostream.h>#define N 4#define DEEP 10typedef struct QNode{int data[N][N];int ancent; //标记方向左上右下分别为1234 5为可以任意方向int x;int y;int deep;struct QNode *next;}QNode, *QueuePtr;typedef struct{QueuePtr head;}LinkQueue;int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};int n=0;//记录步数int x,y;bool check(){//判断是否有路径,根据初始态和目标态的秩序,若不同为奇数或同为偶数,则无路径int temp=A[x][y];int i,j,sum2 = 0,sum1 = 0;int a[N*N],b[N*N];for(i=0;i<N;i++){for(j=0;j<N;j++){a[i*N+j]=A[i][j];}}for(i=0;i<N;i++){for(j=0;j<N;j++){b[i*N+j]=B[i][j];}}for(i=0;i<N*N-1;i++){for(j=i+1;j<N*N;j++){if(a[i]!=temp&&a[j]!=temp&&a[i]>a[j]) sum1++;}}for(i=0;i<N*N-1;i++){for(j=i+1;j<N*N;j++){if(b[i]!=temp&&b[j]!=temp&&b[i]>b[j]) sum2++;}}if((sum1%2==0&&sum2%2==1)||(sum1%2==1&&sum2%2==0)){ return false;}return true;}bool begin_opint(){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(A[i][j]==0){x=i;y=j;return true;}}}return false;}bool compare(int a[N][N]){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(a[i][j]!=B[i][j])return false;}}return true;}bool moveleft(int a[N][N],QueuePtr *b,int x,int y){int k,i,j;if(y==0)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x][y-1];(*b)->data[x][y-1]=k;(*b)->x=x;(*b)->y=y-1;return true;}bool moveup(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(x==0)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x-1][y];(*b)->data[x-1][y]=k;(*b)->x=x-1;(*b)->y=y;return true;}bool movedown(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(x==N-1)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x+1][y];(*b)->data[x+1][y]=k;(*b)->x=x+1;(*b)->y=y;return true;}bool moveright(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(y==N-1)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x][y+1];(*b)->data[x][y+1]=k;(*b)->x=x;(*b)->y=y+1;return true;}bool copy(QueuePtr *a){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++)(*a)->data[i][j]=A[i][j];}return true;}void output(int a[N][N]){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){printf(" %d",a[i][j]);}printf("\n");}printf("\n");}void main(){QueuePtr closed,p,q;LinkQueue open;/*if(!check()){printf("no answer!!\n"); //no answerexit(0);}*/if(!begin_opint()){printf("no 0 opint!!\n"); //确定0点exit(0);}open.head=(QueuePtr)malloc(sizeof(QNode));//头结点open.head->next=NULL;closed=(QueuePtr)malloc(sizeof(QNode));//头结点closed->next=NULL;p=(QueuePtr)malloc(sizeof(QNode));//S0进open表copy(&p);p->x=x;p->y=y;p->ancent=5;p->deep=0; //s0的深度为0p->next=open.head->next;open.head->next=p;while(open.head->next!=NULL){q=open.head->next; //open进closedopen.head->next=q->next; //移除open表头结点q->next=closed->next; //插入closed表的表头closed->next=q;if(q->deep<DEEP){n++;output(q->data);if(compare(q->data)){printf("ok!\n");printf("steps is %d\n",n);exit(0);}//将后继结点放入open表中switch(closed->next->ancent){ //左上右下1234 case 1: p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从右来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=1;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=2;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=4;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);break;case 2:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从下来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=1;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=2;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=3;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);break;case 3:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从左来if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=2;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=3;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=4;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);break;case 4:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从上边来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=1;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=3;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=4;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);break;default:p=(QueuePtr)malloc(sizeof(QNode));//初始情况if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=1;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=2;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveright(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=3;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->ancent=4;p->deep=closed->next->deep+1;p->next=open.head->next;open.head->next=p;}else free(p);break;}}}printf("over deep!!\n");}3 A*算法:#include <stdlib.h>#include <string.h>#include <stdio.h>#include<iostream.h>#define N 4typedef struct QNode{int data[N][N];int ancent; //标记方向左上右下分别为1234 5为可以任意方向int x;int y;int gone; //是否遍历该节点,0未遍历,1遍历过int value; //和目标的状态差=不在位将牌距离和+深度int deep;struct QNode *father; //存放前一节点在"store"数组中的位置struct QNode *next;}QNode, *QueuePtr;typedef struct{QueuePtr head;QueuePtr rear;}LinkQueue;int A[N][N]={{1,2,3,4},{5,10,6,8},{0,9,7,12},{13,14,11,15}};int B[N][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,0}};int x,y;QueuePtr min;//存放最小的结点bool check(){//判断是否有路径,根据初始态和目标态的秩序,若不同为奇数或同为偶数,则无路径int temp=A[x][y];int i,j,sum2 = 0,sum1 = 0;int a[N*N],b[N*N];for(i=0;i<N;i++){for(j=0;j<N;j++){a[i*N+j]=A[i][j];}}for(i=0;i<N;i++){for(j=0;j<N;j++){b[i*N+j]=B[i][j];}}for(i=0;i<N*N-1;i++){for(j=i+1;j<N*N;j++){if(a[i]!=temp&&a[j]!=temp&&a[i]>a[j]) sum1++;}}for(i=0;i<N*N-1;i++){for(j=i+1;j<N*N;j++){if(b[i]!=temp&&b[j]!=temp&&b[i]>b[j]) sum2++;}}if((sum1%2==0&&sum2%2==1)||(sum1%2==1&&sum2%2==0)){ return false;}return true;}bool begin_opint(){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(A[i][j]==0){x=i;y=j;return true;}}}return false;}bool compare(int a[N][N]){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(a[i][j]!=B[i][j])return false;}}return true;}bool moveleft(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(y==0)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x][y-1];(*b)->data[x][y-1]=k;(*b)->x=x;(*b)->y=y-1;return true;}bool moveup(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(x==0)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x-1][y];(*b)->data[x-1][y]=k;(*b)->x=x-1;(*b)->y=y;return true;}bool movedown(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(x==N-1)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x+1][y];(*b)->data[x+1][y]=k;(*b)->x=x+1;(*b)->y=y;return true;}bool moveright(int a[N][N],QueuePtr *b,int x,int y){ int k,i,j;if(y==N-1)return false;for(i=0;i<N;i++){for(j=0;j<N;j++)(*b)->data[i][j]=a[i][j];}k=(*b)->data[x][y];(*b)->data[x][y]=(*b)->data[x][y+1];(*b)->data[x][y+1]=k;(*b)->x=x;(*b)->y=y+1;return true;}bool copy(QueuePtr *a){int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++)(*a)->data[i][j]=A[i][j];}return true;}void output(QueuePtr *p){int i,j;long int n=0;for(;(*p)->father!=NULL;(*p)=(*p)->father,n++){ for(i=0;i<N;i++){for(j=0;j<N;j++){printf(" %d",(*p)->data[i][j]);}printf("\n");}printf("\n");}printf("step is %d\n",n-1);}int getvalue(QueuePtr *p){int count=0;//保存距离bool test=true;//若已找到一个位置的值则继续找下一个//计算不在位的距离和for(int i=0;i<N;i++){for(int j=0;j<N;j++){test=true;for(int k=0;k<N;k++){for(int l=0;l<N;l++){if((i!=(*p)->x||j!=(*p)->y)&&(*p)->data[i][j]==B[k][l]){count=count+abs(i-k)+abs(j-l);test=false;}if(test==false) break;}if(test==false) break;}}}count=count+(*p)->deep;//加上深度值return count;}void main(){QueuePtr closed,p,q;LinkQueue open;if(!begin_opint()){printf("no 0 opint!!\n"); //确定0点exit(0);}/*if(!check()){printf("no answer!!\n"); //确定是否有解exit(0);}*/open.head=open.rear=(QueuePtr)malloc(sizeof(QNode));//头结点open.head->father=NULL;open.rear->next=open.head->next=NULL;closed=(QueuePtr)malloc(sizeof(QNode));//头结点closed->next=NULL;closed->father=NULL;p=(QueuePtr)malloc(sizeof(QNode));//S0进open表copy(&p);p->x=x;p->y=y;p->ancent=5;p->deep=0; //s0的深度为0p->gone=0;p->father=open.head;p->value=getvalue(&p); //p->next=open.head->next;open.head->next=p;open.rear=open.head;//min=p; //初始为s0结点if(compare(p->data)){output(&p);exit(0);}while(open.head->next!=NULL){/*q=open.head->next; //open进closedopen.head->next=q->next; //移除open表头结点q->next=closed->next; //插入closed表的表头closed->next=q;*///寻找最小状态for(min=q=open.head->next;q!=NULL;q=q->next){if(q->value<=min->value&&q->gone==0){min=q;break;}}min->gone=1;//改最小状态已遍历min->father->next=min->next;//在open表中删除找到的最小态min->next=closed->next; //插入closed表的表头//min->father=closed; //?closed->next=min;//空格向4个方向移动switch(closed->next->ancent){case 1: p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从右来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->father=closed->next;p->ancent=1;p->gone=0;p->deep=min->deep+1;p->value=getvalue(&p);p->next=open.rear->next;open.rear->next=p;open.rear=p;//比较输出结果if(compare(p->data)){output(&p);exit(0);}}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->father=closed->next;p->ancent=2;p->gone=0;p->deep=min->deep+1;p->value=getvalue(&p);p->next=open.rear->next;open.rear->next=p;open.rear=p;//比较输出结果if(compare(p->data)){output(&p);exit(0);}}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(movedown(closed->next->data,&p,closed->next->x,closed->next->y)){p->father=closed->next;p->ancent=3;p->gone=0;p->deep=min->deep+1;p->value=getvalue(&p);p->next=open.rear->next;open.rear->next=p;open.rear=p;//比较输出结果if(compare(p->data)){output(&p);exit(0);}}else free(p);break;case 2:p=(QueuePtr)malloc(sizeof(QNode));//祖先结点从下来if(moveleft(closed->next->data,&p,closed->next->x,closed->next->y)){p->father=closed->next;p->ancent=1;p->gone=0;p->deep=min->deep+1;p->value=getvalue(&p);p->next=open.rear->next;open.rear->next=p;open.rear=p;//比较输出结果if(compare(p->data)){output(&p);exit(0);}}else free(p);p=(QueuePtr)malloc(sizeof(QNode));//if(moveup(closed->next->data,&p,closed->next->x,closed->next->y)){p->father=closed->next;p->ancent=2;p->gone=0;p->deep=min->deep+1;p->value=getvalue(&p);p->next=open.rear->next;open.rear->next=p;open.rear=p;//比较输出结果if(compare(p->data)){output(&p);exit(0);。