多种方法解决八数码难题
启发式搜索 八数码问题

启发式搜索1. 介绍八数码问题也称为九宫问题。
在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。
棋盘上还有一个空格(以数字0来表示),与空格相邻的棋子可以移到空格中。
要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
所谓问题的一个状态就是棋子在棋盘上的一种摆法。
解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。
2. 使用启发式搜索算法求解8数码问题。
1) A ,A 星算法采用估价函数()()()()w n f n d n p n ⎧⎪=+⎨⎪⎩, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。
2)宽度搜索采用f(i)为i 的深度,深度搜索采用f(i)为i 的深度的倒数。
3. 算法流程① 把起始节点S 放到OPEN 表中,并计算节点S 的)(S f ;② 如果OPEN 是空表,则失败退出,无解;③ 从OPEN 表中选择一个f 值最小的节点i 。
如果有几个节点值相同,当其中有一个 为目标节点时,则选择此目标节点;否则就选择其中任一个节点作为节点i ;④ 把节点i 从 OPEN 表中移出,并把它放入 CLOSED 的已扩展节点表中;⑤ 如果i 是个目标节点,则成功退出,求得一个解;⑥ 扩展节点i ,生成其全部后继节点。
对于i 的每一个后继节点j :计算)(j f ;如果j 既不在OPEN 表中,又不在CLOCED 表中,则用估价函数f 把 它添入OPEN 表中。
从j 加一指向其父节点i 的指针,以便一旦找到目标节点时记住一个解答路径;如果j 已在OPEN 表或CLOSED 表中,则比较刚刚对j 计算过的f 和前面计算过的该节点在表中的f 值。
如果新的f 较小,则(I)以此新值取代旧值。
八数码问题 实验报告

八数码问题实验报告八数码问题实验报告引言:八数码问题是一种经典的数学难题,在计算机科学领域有着广泛的研究和应用。
本实验旨在通过探索八数码问题的解法,深入理解该问题的本质,并通过实验结果评估不同算法的效率和准确性。
一、问题描述:八数码问题是一个在3×3的棋盘上,由1至8的数字和一个空格组成的拼图问题。
目标是通过移动棋盘上的数字,使得棋盘上的数字排列按照从小到大的顺序排列,最终形成如下的目标状态:1 2 34 5 67 8二、解法探索:1. 深度优先搜索算法:深度优先搜索算法是一种经典的解决拼图问题的方法。
该算法通过不断尝试所有可能的移动方式,直到找到目标状态或者无法再继续移动为止。
实验结果显示,该算法在八数码问题中能够找到解,但由于搜索空间庞大,算法的时间复杂度较高。
2. 广度优先搜索算法:广度优先搜索算法是另一种常用的解决八数码问题的方法。
该算法通过逐层扩展搜索树,从初始状态开始,逐步扩展所有可能的状态,直到找到目标状态。
实验结果显示,该算法能够找到最短路径的解,但同样面临搜索空间庞大的问题。
3. A*算法:A*算法是一种启发式搜索算法,结合了深度优先搜索和广度优先搜索的优点。
该算法通过使用一个估价函数来评估每个搜索状态的优劣,并选择最有希望的状态进行扩展。
实验结果显示,A*算法在八数码问题中表现出色,能够高效地找到最优解。
三、实验结果与分析:通过对深度优先搜索、广度优先搜索和A*算法的实验,得出以下结论:1. 深度优先搜索算法虽然能够找到解,但由于搜索空间庞大,时间复杂度较高,不适用于大规模的八数码问题。
2. 广度优先搜索算法能够找到最短路径的解,但同样面临搜索空间庞大的问题,对于大规模问题效率较低。
3. A*算法在八数码问题中表现出色,通过合理的估价函数能够高效地找到最优解,对于大规模问题具有较好的效果。
四、结论与展望:本实验通过对八数码问题的解法探索,深入理解了该问题的本质,并评估了不同算法的效率和准确性。
八数码难题

arr[sums].nextcost=hn; arr[sums].precost=thisnode->precost+1;// 已 经 走 过 的 路
程
arr[sums].pos=findzero(ch);//空格的位置 for(int j=0;j<3*3;j++)//当前的状态
八数码难题
一、 问题简介 八方块移动游戏要求从一个含 8 个数字(用 1-8 表示)的方块以及一个空格方块(用
0 表示)的 3x3 矩阵的起始状态开始,不断移动该空格方块以使其和相邻的方块互换,直至 达到所定义的目标状态。空格方块在中间位置时有上、下、左、右 4 个方向可移动,在四个 角落上有 2 个方向可移动,在其他位置上有 3 个方向可移动。例如,假设一个 3x3 矩阵的初 始状态为:
return 1; } void init(int ch[],int flag)//初始化数码,键盘输入 {
cout<<"请输入目标状态:("<<3*3<<"个)"<<endl; for( int j=0;j<3*3;j++) cin>>chdes[j]; while(!(isdiff(chdes))) { cout<<"初始化错误,数据不合理!"<<endl; cout<<"请输入目标状态:("<<3*3<<"个)"<<endl; for( j=0;j<3*3;j++) cin>>chdes[j]; } cout<<"请输入初始状态:("<<3*3<<"个)"<<endl; for(j=0;j<3*3;j++) cin>>ch[j]; while(!(isdiff(ch))) { cout<<"初始化错误,数据不合理!"<<endl; cout<<"请输入初始状态:("<<3*3<<"个)"<<endl; for(j=0;j<3*3;j++) cin>>ch[j]; } for(j=0;j<3*3;j++) chbak[j]=ch[j];
八数码问题解析

⼋数码问题解析⼋数码的问题描述为:在3×3的棋盘上,摆有⼋个棋⼦,每个棋⼦上标有1⾄8的某⼀数字。
棋盘中留有⼀个空格,空格⽤-1来表⽰。
空格周围的棋⼦可以移到空格中。
要求解的问题是:给出⼀种初始布局(初始状态)和⽬标布局,找到⼀种最少步骤的移动⽅法,实现从初始布局到⽬标布局的转变。
解决⼋数码的⽅法很多,本⽂采⽤1.⼴度优先搜索的策略,和A星算法两种⽐较常⽤的算法思想解决此问题⼴度优先搜索的策略⼀般可以描述为以下过程:状态空间的⼀般搜索过程OPEN表:⽤于存放刚⽣成的节点CLOSE表:⽤于存放将要扩展或已扩展的节点1. 把初始节点S0放⼊OPEN表,并建⽴只含S0的图,记为GOPEN:=S0,G:=G0(G0=S0)2. 检查OPEN表是否为空,若为空则问题⽆解,退出LOOP:IF(OPEN)=() THEN EXIT(FAIL)3. 把OPEN表的第⼀个节点取出放⼊CLOSE表,记该节点为节点nN:=FIRST(OPEN),REMOVE(n,OPEN),ADD(n,CLOSE)4. 观察节点n是否为⽬标节点,若是,则求得问题的解,退出IF GOAL(n) THEN EXIT(SUCCESS)5. 扩展节点n,⽣成⼀组⼦节点.把其中不是节点n先辈的那些⼦节点记作集合M,并把这些节点作为节点n的⼦节点加⼊G中.EXPAND(n)-->M(mi),G:=ADD(mi,G)6. 转第2步下⾯贴出代码:import timeimport copyclass list():def __init__(self,info): = infoself.front = Noneclass Solution():def __init__(self):self.open = []self.closed = []self.co = 0def msearch(self,S0, Sg):head = list(S0)self.open.append(head)while self.open:n = self.open.pop(0)self.co += 1print('取得节点n:',)if == Sg:print('得到问题的解!')print('⼀共进⾏了',self.co,'次查找')print('该问题的解为:') #对n进⾏while n:print()n = n.frontreturnif n in self.closed:#节点判定是否为扩展问题print('该结点不可扩展')else:print('该节点可扩展')#扩展节点n,#将其⼦节点放⼊open的尾部,#为每⼀个⼦节点设置指向⽗节点的指针nkongdi, nkongdj = 0, 0for i in range(3):for j in range(3):if [i][j] == -1:nkongdi = inkongdj = jln,un,rn,dn =copy.deepcopy(),copy.deepcopy(),copy.deepcopy(),copy.deepcopy()if nkongdj != 0: #rightrn[nkongdi][nkongdj],rn[nkongdi][nkongdj-1] = rn[nkongdi][nkongdj-1],rn[nkongdi][nkongdj]rn = self.link(n,rn)if rn not in self.closed:self.open.append(rn)if nkongdi != 0: #downdn[nkongdi][nkongdj],dn[nkongdi-1][nkongdj] = dn[nkongdi-1][nkongdj],dn[nkongdi][nkongdj]dn = self.link(n,dn)if dn not in self.closed:self.open.append(dn)if nkongdj != 2: #leftln[nkongdi][nkongdj],ln[nkongdi][nkongdj+1] = ln[nkongdi][nkongdj+1],ln[nkongdi][nkongdj]ln = self.link(n,ln)if ln not in self.closed:self.open.append(ln)if nkongdi != 2: #upun[nkongdi][nkongdj],un[nkongdi+1][nkongdj] = un[nkongdi+1][nkongdj],un[nkongdi][nkongdj]un = self.link(n,un)if un not in self.closed:self.open.append(un)self.closed.append(n)def link(self, n ,willn):willnn = list(willn)willnn.front = nreturn willnnif __name__ == '__main__':S0 = [[2,8,3],[1,-1,4],[7,6,5]]S1 = [[1,2,3],[8,-1,4],[7,6,5]]Solution().msearch(S0,S1)代码的⼀些问题:1.对于⼋数码这种状态,可以采⽤⼀些常⽤的压缩策略来减少对内存空间的使⽤。
用A算法解决八数码问题

用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的大小,从最小路径的节点向下进行。
八数码难题

八数码难题一、问题简介八方块移动游戏要求从一个含8个数字(用1-8表示)的方块以及一个空格方块(用0表示)的3x3矩阵的起始状态开始,不断移动该空格方块以使其和相邻的方块互换,直至达到所定义的目标状态。
空格方块在中间位置时有上、下、左、右4个方向可移动,在四个角落上有2个方向可移动,在其他位置上有3个方向可移动。
例如,假设一个3x3矩阵的初始状态为:8 0 32 1 47 6 5目标状态为:1 2 38 0 47 6 5二、算法分析1、问题表示:问题表示的核心是如何存储搜索过程中得到的状态。
本人是这样存储的:对每个状态用一个9位数存储,例如:把初始状态:8 0 32 1 47 6 5存储为一个9位数:8032147652、问题分析想法一:采用插入排序的方法,八数码问题好比是一列数,将各个行列的数字按大小排列,在插入的时候考虑方向性和比较性,对每个数字节点设置前后左右四个属性,分别在初始状态比较各自队列的大小,比如按照左前右后顺时针的方向依次比较和移动,设置哨兵,循环比较,最后得到的序列也就是八数码问题迎刃而解了。
想法二:采用prolog语言表示,Prolog(Programming in Logic的缩写)是一种逻辑编程语言。
它建立在逻辑学的理论基础之上,最初被运用于自然语言等研究领域。
现在它已广泛的应用在人工智能的研究中,它可以用来建造专家系统、自然语言理解、智能知识库等。
2、解题算法:广度搜索常用的优化方法:哈希表法——记录队列中已有节点,用于判断是否需要扩展节点。
A*算法——构造估价函数。
双向广度优先搜索——从源节点、目标节点一起开始搜索。
三、算法实现本程序用了广度优先搜索这种策略进行搜索,且其搜索深度限制在1000内,其代码实现如下:#include "stack1.h"#include<time.h>stack open,closed;//表的基本操作void swap(int &a,int &b)//比较数字{int bak=a; a=b; b=bak;}int isok(int pos)//界限判断{return pos>=0&&pos<3*3;}int isdiff(int ch[])//判断输入数码是否合法{for(int i=0;i<3*3-1;i++)for(int j=i+1;j<3*3;j++)if(ch[i]==ch[j]||!isok(i)||!isok(j))return 0;return 1;}void init(int ch[],int flag)//初始化数码,键盘输入{cout<<"请输入目标状态:("<<3*3<<"个)"<<endl;for( int j=0;j<3*3;j++)cin>>chdes[j];while(!(isdiff(chdes))){cout<<"初始化错误,数据不合理!"<<endl;cout<<"请输入目标状态:("<<3*3<<"个)"<<endl;for( j=0;j<3*3;j++)cin>>chdes[j];}cout<<"请输入初始状态:("<<3*3<<"个)"<<endl;for(j=0;j<3*3;j++)cin>>ch[j];while(!(isdiff(ch))){cout<<"初始化错误,数据不合理!"<<endl;cout<<"请输入初始状态:("<<3*3<<"个)"<<endl;for(j=0;j<3*3;j++)cin>>ch[j];}for(j=0;j<3*3;j++)chbak[j]=ch[j];}int findnext(int pos,int step)//找到移动位置{if(step>=0&&step<4) //四个方向移动{switch(step){case 0:if(isok(pos-3))return pos-3;return -1;break;case 1:if(isok(pos+1)&&pos/3==(pos+1)/3)return pos+1;return -1;break;case 2:if(isok(pos+3))return pos+3;return -1;break;case 3:if(isok(pos-1)&&pos/3==(pos-1)/3)return pos-1;return -1;break;}}return -1;}int getnum(int pos){if(isok(pos)){for(int i=0;i<3*3;i++)if(chdes[i]==ch[pos])return(abs(i/3-pos/3)+abs(i%3-pos%3));}return 0;}int getallnum(){int sum=0;for(int i=0;i<3*3;i++)sum+=getnum(i);return sum;}int findzero(int ch[]){for(int i=0;i<3*3;i++)if(ch[i]==0)return i;return -1;}void showparent(node *root)//递归方式显示结果路径{if(root->pre!=-1){showparent(&arr[root->pre]);root->show();cout<<"--第"<<root->precost+1<<"步--"<<endl;}}void showchar(int ch[])//显示一个状态{for(int i=0;i<3*3;i++){cout<<ch[i]<<" ";if((i+1)%3==0)cout<<endl;}}int getpath(node *thisnode,int &sums)//递归方式搜索最优路径{if(sums>=9*maxsize/10){cout<<"应该是没有解路径,需要太多空间!(需存储"<<jiecheng(3*3)<<" 个状态!)"<<endl;return 0;}else{for(int i=0;i<3*3;i++)ch[i]=thisnode->ch1[i];for(i=0;i<4;i++)//从四个方位搜索{int pos1=findnext(thisnode->pos,i);//搜索的位置if(pos1!=-1)//搜索的位置合法{swap(ch[pos1],ch[thisnode->pos]);//移动数码int hn=getallnum();if(hn==0){cout<<"a solution is :"<<endl;showchar(chbak);cout<<"--第1步--"<<endl;showparent(thisnode);showchar(chdes);return 1;}elseif(hn>0)//如果没有到达目标状态{arr[sums].nextcost=hn;arr[sums].precost=thisnode->precost+1;//已经走过的路程arr[sums].pos=findzero(ch);//空格的位置for(int j=0;j<3*3;j++)//当前的状态arr[sums].ch1[j]=ch[j];arr[sums].pre=thisnode->id;if(!(open.cmp(&arr[sums])||closed.cmp(&arr[sums]))){open.insert(&arr[sums]);sums++;}}swap(ch[pos1],ch[thisnode->pos]);}}if(!open.isempty()){node *tem=open.del();closed.insert1(tem);getpath(tem,sums);}else{cout<<"没有解路径!"<<endl;return 0;}}return 0;}void main(){char cls[4]="cls",input='1';int flag=1,sum=1;while(input>='1'&&input<='4'){open.clear();closed.clear();sum=1;flag=1;select();cin>>input;if(input>='1'&&input<='4'){switch(input){case '1':init(ch,0);break;case '2':system(cls);flag=2;}if(flag==1){for(int i=0;i<maxsize;i++)arr[i].id=i;arr[0].precost=0;arr[0].pre=-1;arr[0].pos=findzero(ch);arr[0].nextcost=getallnum();for(i=0;i<3*3;i++)arr[0].ch1[i]=ch[i];open.insert(&arr[0]);node *p=open.del();closed.insert1(p);cout<<"目标状态:"<<endl;showchar(chdes);cout<<"初始状态:"<<endl;showchar(chbak);if(arr[0].nextcost>0)getpath(&arr[0],sum);elsecout<<"初始状态为目标状态!"<<endl;}}}}四、实验分析实验界面为:本实验采取表的排序,并利用广度优先搜索来查找路径,基本实现了实验要求,仍有不完善之处,仍需继续改正。
A星算法求解八数码问题

A*算法求解八数码问题1、八数码问题描述所谓八数码问题起源于一种游戏:在一个3×3的方阵中放入八个数码1、2、3、4、5、6、7、8,其中一个单元格是空的.将任意摆放的数码盘(城初始状态)逐步摆成某个指定的数码盘的排列(目标状态),如图1所示图1 八数码问题的某个初始状态和目标状态对于以上问题,我们可以把数码的移动等效城空格的移动.如图1的初始排列,数码7右移等于空格左移.那么对于每一个排列,可能的一次数码移动最多只有4中,即空格左移、空格右移、空格上移、空格下移。
最少有两种(当空格位于方阵的4个角时).所以,问题就转换成如何从初始状态开始,使空格经过最小的移动次数最后排列成目标状态。
2、八数码问题的求解算法2。
1 盲目搜索宽度优先搜索算法、深度优先搜索算法2。
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*算法.针对八数码问题启发函数设计如下:f(n)=d(n)+p(n) (4)其中A*算法中的g(n)根据具体情况设计为d(n),意为n节点的深度,而h(n)设计为图2 A*算法流程图p(n),意为放错的数码与正确的位置距离之和。
八数码问题

人工智能实验报告一.八数码问题及分析:八数码问题也称为九宫问题。
在3×3的棋盘,摆有八个数码,分别为1至8的某一数字,数字各不相同。
棋盘上还有一个空格,与空格相邻的数码可以移到空格中。
要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动数码步数最少的移动步骤。
其中,问题的一个状态就是数码在棋盘上的一种摆法。
数码移动后,状态就会发生改变。
解八数码问题实际上就是找出从初始状态到达目标状态所经过的一系列中间过渡状态。
八数码问题一般使用搜索法来解。
搜索法有广度优先搜索法、深度优先搜索法、A*算法等。
本次试验采用局部择优A算法(即启发函数的有界深度搜索算法)。
二.实验说明:因为在学生社团工作,中间一段时间一直不能够和大家一起准备本次实验,也不好意思拖延大家的进度,于是,我选在工作之后自己一个人做本次试验,但因为技术方面的不够成熟,实际上我查找了许多资料,同时向学长请教用C++builder实现了局部最优的算法。
在算法分析中主要比较讨论了广度优先算法和A*算法,也是由A*算法得到的灵感利用启发函数,但最终的搜索却选择了有界深度的方式。
这是因为八数码问题相对简单,利用有界能够很好的控制算法的中止。
.软件环境:Borland C++ Builder 6三.数据结构设计1.用二唯数组定义棋子的变换(空格的左移、右移、上移、下移)2.定义权值3.定义指向父亲和孩子的指针。
程序如下(Tlist.h):#ifndef KTListH#define KTListH//节点模板类(如KTNode<int>* Paths; 使用)template <class DATATYPE>class KTNode{public:DATATYPE Data; //可变数据类型的节点数据int Weight; //排序用的权重KTNode* Next; //指向下一个节点的指针KTNode* Prior; //指向上一个节点的指针KTNode(){Weight = 0;}//拷贝构造函数KTNode(KTNode& S){Data=S.Data;Weight=S.Weight;Next=S.Next;Prior=S.Prior;}KTNode operator=(KTNode S) //重载运算符,使两个KTNode对象能相互赋值{Data=S.Data;Weight=S.Weight;Next=S.Next;Prior=S.Prior;return *this; //调用拷贝构造函数}};四.算法分析:I)广度优先搜索法1.广度优先搜索算法的基本步骤1)建立一个队列,将初始结点入队,并设置队列头和尾指针2)取出队列头(头指针所指)的结点进行扩展,从它扩展出子结点,并将这些结点按扩展的顺序加入队列。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
汇报时间:2018年10月 汇报人:马玥 PPT制作者:何帅帅 代码编辑调试者:尹迅、马玥
01 问题重述 Problem Retelling
目 录
CONTENTS
02 问题分析 Problem Analysis
03 宽度优先 Width First
04 深度优先 Depth First
05 启发式搜索
黑色数字表示不 在位的将牌数 A(6) 2 8 3 1 6 4 7 5 D(5) 2 8 3 3 1 4 7 6 5 G(6) 8 3 2 1 4 7 6 5 H(7) 2 8 3 7 1 4 6 5
S(4) 初始 2 8 3 1 1 6 4 7 5 B(4) 2 2 8 3 1 4 7 6 5 E(5) 2 1 8 7 6 I(5) 2 1 8 7 6 K(5) 1 2 8 7 6 4 C(6) 2 8 3 1 6 4 7 5 F(6) 2 8 3 1 4 7 6 5 J(7) 2 3 1 8 4 7 6 5
Heuristic Search
问题重述
Problem Retelling
八数码问题描述
3×3九宫棋盘,放置数码为1 -8的8个棋牌,剩下一个空格,只能通过棋牌向空格的移动 来改变棋盘的布局。 要求:根据给定初始布局(即初始状态)和目标布局(即目标状态),如何移动棋牌才能从 初始布局到达目标布局,找到合法的走步序列。
启发式搜索
Heuristic Search
启发式搜索算法解决八数码难题 有序搜索(A算法)
评价函数:f(n) = g(n) + h(n) (其中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值最小的节点来优先扩展。
谢谢观赏
2 B C 2 8 3 h*=4,g*=1 2 8 3 1 4 W=3 1 6 4 P=4 7 6 5 f=5 7 5 E 3 2 3 1 8 4 7 6 5
h*=3,g*=2 W=3 P=3 f=5
W=5 P=6 f=7
F 2 8 3 1 4 7 6 5
W=4 P=5 f=7
G h*=2,g*=3
…
4
2 8 3 1 6 4 7 5 2 8 3 6 4 1 7 5
…
1 2 3 7 8 4 6 5
1 2 3 8 4 7 6 5
…
…
设深度界限dm=4
3 2 8 3 1 6 4 7 5 4 2 8 3 1 6 4 7 5 2 8 3 6 4 1 7 5 5 2 8 3 1 6 4 7 5 2 8 3 1 6 7 5 4 7 8 3 2 1 4 7 6 5 8 3 2 1 4 7 6 5
八数码难题(8-puzzle problem)
2
8
3
1
2
3
1
7
6
4
5
8
7 6
4
5
(初始状态)
(目标状态)
宽度优先
Width First
宽度优先搜索算法解决八数码难题
它是从根节点(起始节点)开始,按层进行搜索,也就是按 层来扩展节点。所谓按层扩展,就是前一层的节点扩展完毕后才 进行下一层节点的扩展,直到得到目标节点为止。 这种搜索方式的优点是,只要存在有任何解答的话,它能保 证最终找到由起始节点到目标节点的最短路径的解,但它的缺点 是往往搜索过程很长。
深度优先搜索算法解决八数码难题
它是从根节点开始,首先扩展最新产生的节点,即沿着搜索树的深度发展下 去,一直到没有后继结点处时再返回,换一条路径走下去。就是在搜索树的每一层 始终先只扩展一个子节点,不断地向纵深前进直到不能再前进(到达叶子节点或受 到深度限制)时,才从当前节点返回到上一级节点,沿另一方向又继续前进。这种 方法的搜索树是从树根开始一枝一枝逐渐形成的。 由于一个有解的问题树可能含有无穷分枝,深度优先搜索如果误入无穷分枝 (即深度无限),则不可能找到目标节点。为了避免这种情况的出现,在实施这一 方法时,定出一个深度界限,在搜索达到这一深度界限而且尚未找到目标时,即返 回重找,所以,深度优先搜索策略是不完备的。另外,应用此策略得到的解不一定 是最佳解(最短路径)。
17 1 2 3 8 4 7 6 5
从图中得,解的路径是S->3->8->17
宽度优先搜索算法代码演示
宽度优先搜索的性质
• 当问题有解时,一定能找到解 • 当问题为单位耗散值,且问题有解时,一定能找到最优 解 • 方法与问题无关,具有通用性 • 效率较低 • 属于图搜索方法
深度优先
Depth First
13 1 2 3 8 4 7 6 5
2 8 3 7 1 4 6 5 2 8 3 7 1 4 6 5
11 2 8 3 1 4 5 7 6 2 8 3 1 4 5 7 6
1 2 3 7 8 4 6 5
1 2 3 8 4 7 6 5
深度优先搜索算法代码演示
深度优先搜索的性质
• 一般不能保证找到最优解 • 当深度限制不合理时,可能找不到解,可以将算法改为 可变深度限制 • 最坏情况时,搜索空间等同于穷举 • 与回溯法的差别:图搜索 • 是一个通用的与问题无关的方法
h(n)=P(n)的搜索树
H 2 3 1 8 4 7 6 5
A*搜索算法代码演示
在八数码难题中, 令估价函数 f(n)=d(n)+p(n) ,启发函数h(n)=p(n),p(n)为不在 位的棋子与其目标位置的距离之和,则有p(n)≤h*(n),满足A*算法的限制条件。 w(n)表示不在位的棋子数,不够贴切,错误选用节点加以扩展。 更接近于h*(n)的 h(n),其值是节点n与目标状态节点相比较,每个错位棋子在假设不受阻拦的情况 下,移动到目标状态相应位置所需走步的总和。(n)比w(n)更接近于h*(n),因为p(n) 不仅考虑了错位因素,还考虑了错位的距离(移动次数)。 说明h值越大,启发功 能越强, 搜索效率越高.特别地: (1)h(n)=h*(n) 搜索仅沿最佳路径进行, 效率最高. (2)h(n)=0 无启发信息, 盲目搜索, 效率低. (3)h(n)>h*(n)
2 3 1 8 4 7 6 5 2 2 8 3 1 4 7 6 5 12 2 3 1 8 4 7 6 5
1
1 2 3 8 4 7 6 5 2 3 1 8 4 7 6 5 (目标状态)
6 2 8 3 1 4 7 6 5 1 4 3 7 6 5 2 8 1 4 3 7 6 5
W=3 P=5 f=7
W=5 P=6 f=7
S 1 初始 2 8 3 1 6 4 7 5
h*=5,g*=0 W=4 P=5 f=5
h*--从节点n到目标节点g 的最短路径耗散值。 g*--从初始节点s到节点n 的最短路径耗散值。 W—不在位将牌数之和。 P—每个不在位将牌移动 到目标状态相应位置所 需走步的总和。
6 2 8 3 1 4 7 6 5
8 1 2 3 8 4 7 6 5
10 2 8 3 1 6 4 7 5
11 2 8 3 1 6 4 7 5
12 2 8 3 1 4 5 7 6
13 2 8 1 4 3 7 6 5
14
15
8 3 2 1 4 7 6 5
2 8 3 7 1 4 6 5
16 1 2 3 7 8 4 6 5
开始
有序搜索算法框图
把S放入OPEN表,计算 估价函数f(s)
OPEN表为空?
是
失败
否
选取OPEN表中f值最小的节点i放入CLOSE表
i为目标节点吗
是
失败
否 扩展i,得后继结点j,计算f(j),提供返回节点i的指 针,利用f(j)对OPEN表重新排序,调整亲子关系及指 针
1 2 3 8 4 7 6 5 (目标状态)
深度优先搜索算法解决八数码难题
1 2 3
8
7 6
4
5 2 2 8 3 1 4 7 6 5 2 8 3 1 4 7 6 5 2 8 3 1 4 7 6 5
2 3 1 8 4 7 6 5 2 3 1 8 4 7 6 5
1
(目标状态) 3 2 8 3 1 6 4 7 5 2 8 3 1 6 4 7 5
2 3 1 8 4 7 6 5 1 2 3 8 4 7 6 5
开始 读入棋局初始状态
A*算法框图
是否可解?
是 初始状态加入OPEN表
否
在OPEN表中找到评价值最小的节点,作为当前节点 是 是目标节点
否 扩展新状态,把不重复的新状态加入OPEN表中 当前节点从OPEN表移除 输出结果 结束
1 2 3 8 4 7 6 5 (目标状态)
黑色数字表示不 在位的将牌数 A 2 8 3 1 6 4 7 5 D 2 8 3 1 4 7 6 5
s
宽度优先搜索
2 2 8 3 1 4 7 6 5 5 2 8 3 1 6 4 7 5
2 3 1 8 4 7 6 5
1
1 2 3 8 4 7 6 5 4 2 3 1 8 4 7 6 5 9 2 3 4 1 8 7 6 5 (目标状态)
2 3 1 8 4 7 6 5
7 2 8 3 1 4 7 6 5
3
3 4 5
3 5 4 5
3 4 5 6
L(5) 1 2 3 7 8 4 7 6 5