实验一 启发式搜索算法

合集下载

启发式搜索实验讲解

启发式搜索实验讲解

启发式搜索实验讲解实验三搜索推理技术启发式搜索算法—A*算法1.实验目的(1)了解搜索推理的相关技术;(2)掌握启发式搜索算法或者基于规则推理的分析方法。

2.实验内容(2个实验内容可以选择1个实现)(1)启发式搜索算法。

熟悉和掌握启发式搜索的定义、估价函数和算法过程,并求解博弈问题,理解求解流程和搜索顺序;(2)产生式系统实验。

熟悉和掌握产生式系统的运行机制,掌握基于规则推理的基本方法。

3.实验报告要求(1)简述实验原理及方法,并请给出程序设计流程图。

(A-Star)算法是一种静态路网中求解最短路最有效的直接搜索方法。

公式表示为:f(n)=g(n)+h(n),其中f(n) 是从初始点经由节点n到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n) 是从n到目标节点最佳路径的估计代价。

保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:估价值h(n)<= n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。

但能得到最优解。

并且如果h(n)=d(n),即距离估计h(n)等于最短距离,那么搜索将严格沿着最短路径进行,此时的搜索效率是最高的。

然后我们通过图文结合的形式来解释下,如下图:图中有这么几个要点先需要了解:1、类似迷宫图,分开始节点(start)、障碍物、结束节点(end),我们需要从start节点探寻一条到end节点的路线2、对于探寻的每一步,都会以当前节点为基点,扫描其相邻的八个节点3、计算当前节点与start节点及到end的距离4、计算出最短路径如果明白了上面的场景描述,下面就可以进行分析了。

在A*算法中,核心思想是一个公式,上面已经提到过:f(n)=g(n)+h(n) (2)源程序清单:package com.itxxz.ui.suanfa.astar;import java.util.Iterator;import java.util.LinkedList;import java.util.Queue;import com.itxxz.ui.suanfa.astar.Point;public class ItxxzAstar {// 开始节点private Point startPoint = null;// 当前节点private Point endPoint = null;// 结束节点private Point currentPoint = null;// 最短距离坐标节点private Point shortestFPoint = null;// 迷宫数组地图private static final int[][] mazeArray = {{ 1, 0, 0, 0, 0 },{ 1, 0, 2, 0, 0 },{ 1, 0, 0, 0, 1 },{ 1, 0, 0, 0, 0 },{ 1, 1, 1, 1, 0 },{ 1, 0, 0, 0, 0 },{ 3, 0, 1, 1, 1 } };// 迷宫坐标对象private Point[][] mazePoint = null;// 开启队列,用于存放待处理的节点Queue openQueue = null;// 关闭队列,用于存放已经处理过的节点Queue closedQueue = null;// 起始节点到某个节点的距离int[][] FList = null;// 某个节点到目的节点的距离int[][] GList = null;// 起始节点经过某个节点到目的节点的距离int[][] HList = null; /*** 构造函数** @param maze* 迷宫图* @param startPoint* 起始节点* @param endPoint* 结束节点*/public ItxxzAstar(Point[][] mazePoint, Point startPoint, Point endPoint) { this.mazePoint = mazePoint;this.startPoint = startPoint;this.endPoint = endPoint;openQueue = new LinkedList();openQueue.offer(startPoint);closedQueue = new LinkedList();FList = new int[mazePoint.length][mazePoint[0].length];GList = new int[mazePoint.length][mazePoint[0].length];HList = new int[mazePoint.length][mazePoint[0].length];for (int i = 0; i < mazePoint.length; i++) {for (int j = 0; j < mazePoint[0].length; j++) {FList[i][j] = Integer.MAX_V ALUE;GList[i][j] = Integer.MAX_V ALUE;HList[i][j] = Integer.MAX_V ALUE;}}// 起始节点到当前节点的距离GList[startPoint.getX()][startPoint.getY()] = 0;// 当前节点到目的节点的距离HList[startPoint.getX()][startPoint.getY()] = getPointDistance(startPoint.getX(), startPoint.getY(), endPoint.getX(),endPoint.getY());// f(x) = g(x) + h(x)FList[startPoint.getX()][startPoint.getY()] = GList[startPoint.getX()][startPoint .getY()] + HList[startPoint.getX()][startPoint.getY()];}/*** 计算当前坐标与结束坐标之间的距离** 计算方法为每向相信坐标移动一次算作一个距离单位**/private int getPointDistance(int current_x, int current_y, int end_x,int end_y) {return Math.abs(current_x - end_x) + Math.abs(current_y - end_y);}/*** 数组迷宫地图** 0、可通行1、障碍2、开始节点3、结束节点**/public static void main(String[] args) {// 创建节点迷宫图Point[][] mazePoint = new Point[mazeArray.length][mazeArray[0].length];for (int i = 0; i < mazePoint.length; i++) {for (int j = 0; j < mazePoint[0].length; j++) {mazePoint[i][j] = new Point(i, j, mazeArray[i][j]);}}Point start = mazePoint[1][2];Point end = mazePoint[6][0];ItxxzAstar star = new ItxxzAstar(mazePoint, start, end);star.start();System.out.println(mazeArray.length + "," + mazeArray[0].length);star.printPath();}/*** 开始迷宫搜索**/public void start() {while ((currentPoint = findShortestFPoint()) != null) {if (currentPoint.getX() == endPoint.getX()&& currentPoint.getY() == endPoint.getY())return;updateNeighborPoints(currentPoint);}}/*** 获取距离最短的坐标点**/public Point findShortestFPoint() {currentPoint = null;shortestFPoint = null;int shortestFValue = Integer.MAX_V ALUE;Iterator it = openQueue.iterator();while (it.hasNext()) {currentPoint = it.next();if (FList[currentPoint.getX()][currentPoint.getY()] <= shortestFValue) { shortestFPoint = currentPoint;shortestFValue = FList[currentPoint.getX()][currentPoint.getY()];}}if (shortestFValue != Integer.MAX_V ALUE) {System.out.println("【移除节点】:" + shortestFPoint.getValue() + "["+ shortestFPoint.getX() + ","+ shortestFPoint.getY() + "]");openQueue.remove(shortestFPoint);closedQueue.offer(shortestFPoint);}return shortestFPoint;}/*** 更新临近节点*/private void updateNeighborPoints(Point currentPoint) {int current_x = currentPoint.getX();int current_y = currentPoint.getY();System.out.println("当前节点:[" + current_x + "," + current_y + "]");// 上if (checkPosValid(current_x - 1, current_y)) {System.out.print("上");updatePoint(mazePoint[current_x][current_y],mazePoint[current_x - 1][current_y]);}// 下if (checkPosValid(current_x + 1, current_y)) { System.out.print("下");updatePoint(mazePoint[current_x][current_y], mazePoint[current_x + 1][current_y]);}// 左if (checkPosValid(current_x, current_y - 1)) { System.out.print("左");updatePoint(mazePoint[current_x][current_y], mazePoint[current_x][current_y - 1]);}// 右if (checkPosValid(current_x, current_y + 1)) { System.out.print("右");updatePoint(mazePoint[current_x][current_y], mazePoint[current_x][current_y + 1]);}System.out.println("---------------");}/*** 检查该节点是否有效**/private boolean checkPosValid(int x, int y) { // 检查x,y是否越界,并且当前节点不是墙if ((x >= 0 && x < mazePoint.length)&& (y >= 0 && y < mazePoint[0].length)&& (mazePoint[x][y].getValue() != 1)) {// 检查当前节点是否已在关闭队列中,若存在,则返回"false"Iterator it = closedQueue.iterator();Point point = null;while (it.hasNext()) {if ((point = it.next()) != null) {if (point.getX() == x && point.getY() == y)return false;}}return true;}return false;}/*** 更新当前节点*/private void updatePoint(Point lastPoint, Point currentPoint) {int last_x = lastPoint.getX();int last_y = lastPoint.getY();int current_x = currentPoint.getX();int current_y = currentPoint.getY();// 起始节点到当前节点的距离int temp_g = GList[last_x][last_y] + 1;// 当前节点到目的位置的距离System.out.print(" [" + current_x + "," + current_y + "]"+ mazePoint[current_x][current_y].getValue());int temp_h = getPointDistance(current_x, current_y, endPoint.getX(),endPoint.getY());System.out.println("到目的位置的距离:" + temp_h);// f(x) = g(x) + h(x)int temp_f = temp_g + temp_h;System.out.println("f(x) = g(x) + h(x) :" + temp_f + "=" + temp_g + "+"+ temp_h);// 如果当前节点在开启列表中不存在,则:置入开启列表,并且“设置”// 1) 起始节点到当前节点距离// 2) 当前节点到目的节点的距离// 3) 起始节点到目的节点距离if (!openQueue.contains(currentPoint)) {openQueue.offer(currentPoint);currentPoint.setFather(lastPoint);System.out.println("添加到开启列表:" + currentPoint.getValue() + "["+ currentPoint.getX() + "," + currentPoint.getY() + "]");// 起始节点到当前节点的距离GList[current_x][current_y] = temp_g;// 当前节点到目的节点的距离HList[current_x][current_y] = temp_h;// f(x) = g(x) + h(x)FList[current_x][current_y] = temp_f;} else {// 如果当前节点在开启列表中存在,并且,// 从起始节点、经过上一节点到当前节点、至目的地的距离< 上一次记录的从起始节点、到当前节点、至目的地的距离,// 则:“更新”// 1) 起始节点到当前节点距离// 2) 当前节点到目的节点的距离// 3) 起始节点到目的节点距离if (temp_f < FList[current_x][current_y]) {// 起始节点到当前节点的距离GList[current_x][current_y] = temp_g;// 当前节点到目的位置的距离HList[current_x][current_y] = temp_h;// f(x) = g(x) + h(x)FList[current_x][current_y] = temp_f;// 更新当前节点的父节点currentPoint.setFather(lastPoint);}System.out.println("currentPoint:" + currentPoint.getValue() + "["+ currentPoint.getX() + "," + currentPoint.getY() + "]");System.out.println("currentPoint.father:"+ currentPoint.getFather().getValue() + "["+ currentPoint.getFather().getX() + ","+ currentPoint.getFather().getY() + "]");}}/*** 打印行走路径**/public void printPath() {System.out.println("================ 开始打印行走路径【用8 表示】================");Point father_point = null;int[][] result = newint[mazeArray.length][mazeArray[0].length];for (int i = 0; i < mazeArray.length; i++) {for (int j = 0; j < mazeArray[0].length; j++) {result[i][j] = 0;}}int step = 0;father_point = mazePoint[endPoint.getX()][endPoint.getY()];while (father_point != null) {System.out.println("【father_point】" + father_point.getValue() + "["+ father_point.getX() + "," + father_point.getY() + "]");if (father_point.equals(startPoint))result[father_point.getX()][father_point.getY()] = 2;else if (father_point.equals(endPoint)) {result[father_point.getX()][father_point.getY()] = 3;step++;} else {result[father_point.getX()][father_point.getY()] = 8;step++;}father_point = father_point.getFather();}// 打印行走步数System.out.println("step is : " + step);for (int i = 0; i < mazeArray.length; i++) {for (int j = 0; j < mazeArray[0].length; j++) {System.out.print(result[i][j] + " ");}System.out.println();}}}(3)实验结果及分析。

启发式搜索算法心得体会

启发式搜索算法心得体会

启发式搜索算法心得体会启发式搜索算法是一种通过推测来指导搜索方向的方法,它根据问题的特点和先前的知识进行启发式的搜索,以找到问题的最优解。

在实际应用中,启发式搜索算法被广泛应用于解决各种问题,如求解迷宫、规划路径等。

通过学习和理解启发式搜索算法,我获得了以下几点体会。

首先,启发式搜索算法的核心是启发函数的设计。

启发函数用于评估搜索节点的优劣,以决定搜索的方向。

好的启发函数能够明确指导搜索过程,减少不必要的搜索节点,提高搜索的效率。

在设计启发函数时,我们需要考虑问题的特点和约束条件,合理选择启发函数的评估指标,并通过启发函数的计算方法来优化搜索过程。

其次,启发式搜索算法在问题求解中的表现受到启发函数的影响。

不同的启发函数会导致不同的搜索策略和结果。

因此,在实际应用中,我们需要根据问题的不同特点和求解要求,设计适合的启发函数。

例如,在解决迷宫问题时,可以根据迷宫的布局和目标位置,设计一种启发函数来估计当前节点到目标的距离,以此指导搜索前进的方向。

再次,启发式搜索算法是一种权衡准确性和效率的方法。

通常情况下,启发式搜索算法能够在较短的时间内找到较优解,但并不能保证找到问题的最优解。

这是因为启发式搜索算法通过启发函数进行估计,存在一定的不确定性。

因此,在实际应用中,我们需要根据问题的实际需求,平衡准确性和效率的关系,选择适合的搜索算法和启发函数。

最后,启发式搜索算法是一个不断迭代的过程。

通过不断优化启发函数和搜索策略,我们可以不断改进算法的性能和效果。

在实际应用中,我们可以通过实验和反馈来不断改进启发函数和搜索策略,以逐步提高算法的性能和效果。

此外,启发式搜索算法也可以与其他算法结合使用,形成更加强大和高效的问题求解方法。

总之,通过学习和理解启发式搜索算法,我认识到它在问题求解中的重要性和广泛应用。

通过合理设计启发函数,我们能够明确指导搜索过程,提高搜索效率。

然而,启发式搜索算法也存在一定的局限性,需要在准确性和效率之间进行权衡。

启发式搜索A星算法

启发式搜索A星算法

启发式搜索——初识A*算法A*在游戏中有它很典型的用法,是人工智能在游戏中的代表。

A*算法在人工智能中是一种典型的启发式搜索算法,为了说清楚A*算法,先说说何谓启发式算法。

一、何谓启发式搜索算法在说它之前先提提状态空间搜索。

状态空间搜索,如果按专业点的说法,就是将问题求解过程表现为从初始状态到目标状态寻找这个路径的过程。

通俗点说,就是在解一个问题时,找到一个解题的过程,应用这个过程可以从求解的开始得到问题的结果。

由于求解问题的过程中分支有很多,主要是求解过程中求解条件的不确定性、不完备性造成的,使得求解的路径很多,这样就构成了一个图,我们说这个图就是状态空间。

问题的求解实际上就是在这个图中找到一条路径可以从开始到结果。

这个寻找的过程就是状态空间搜索。

常用的状态空间搜索有深度优先和广度优先。

广度优先是从初始状态一层一层向下找,直到找到目标为止。

深度优先是按照一定的顺序,先查找完一个分支,再查找另一个分支,直至找到目标为止。

这两种算法在数据结构书中都有描述,可以参看这些书得到更详细的解释。

前面说的广度和深度优先搜索有一个很大的缺陷就是:他们都是在一个给定的状态空间中穷举。

这在状态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不可预测的情况下就不可取了。

他们的效率实在太低,甚至不可完成。

在这里就要用到启发式搜索了。

启发式搜索就是在状态空间中搜索时,对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直至找到目标。

这样可以省略大量无谓的搜索路径,提高了效率。

在启发式搜索中,对位置的估价是十分重要的。

采用了不同的估价可以有不同的效果。

我们先看看估价是如何表示的。

启发中的估价是用估价函数表示的,如:f(n) = g(n) + h(n)其中f(n)是节点n的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n节点到目标节点最佳路径的估计代价。

在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。

启发式算法详细讲解

启发式算法详细讲解

启发式算法详细讲解
启发式算法(Heuristic Algorithm)也被称为启发算法或者近似算法,是一种通过启发式搜索的方式来解决问题的算法。

启发式算法与精确算法不同,它不保证最优解,但通常能够在合理的时间内找到较好的解。

启发式算法的基本思想是根据问题的特性和经验,使用一些启发式的规则或策略来指导搜索过程,以此来引导算法在搜索空间中找到可能更接近最优解的解。

具体来说,启发式算法通常包含以下步骤:
1. 初始解生成:通过某种方法生成一个初始解,可以是随机生成、基于经验的启发式规则生成等。

2. 邻域搜索:在当前解的周围搜索邻域解,通过一系列的局部搜索操作,如交换、插入、删除等,来生成新的解。

3. 评估函数:对新生成的解进行评估,评估函数用来衡量解的好坏程度,可以是目标函数值、代价函数值、质量评估值等。

4. 更新解:根据评估函数的结果,更新当前解为评估值更好的解。

5. 终止条件:根据预设的终止条件,判断是否终止搜索过程。

终止条件可以是找到满足要求的解或达到最大迭代次数等。

启发式算法的性能依赖于初始解的生成和邻域搜索操作的设计,以及评估函数的准确性。

在实际应用中,针对不同的问题,可以使用不同的启发式算法。

常见的启发式算法有贪婪算法、模拟退火算法、遗传算法、禁忌搜索等。

需要注意的是,启发式算法不能保证找到全局最优解,但可以在合理的时间内找到接近最优解的解。

启发式算法常常应用于那些NP难问题或解空间很大的问题中,可以在较短的时间内找到近似最优解,是一种非常实用的算法设计思想。

启发式搜索A星算法

启发式搜索A星算法

启发式搜索——初识A*算法A*在游戏中有它很典型的用法,是人工智能在游戏中的代表。

A*算法在人工智能中是一种典型的启发式搜索算法,为了说清楚A*算法,先说说何谓启发式算法。

一、何谓启发式搜索算法在说它之前先提提状态空间搜索。

状态空间搜索,如果按专业点的说法,就是将问题求解过程表现为从初始状态到目标状态寻找这个路径的过程。

通俗点说,就是在解一个问题时,找到一个解题的过程,应用这个过程可以从求解的开始得到问题的结果。

由于求解问题的过程中分支有很多,主要是求解过程中求解条件的不确定性、不完备性造成的,使得求解的路径很多,这样就构成了一个图,我们说这个图就是状态空间。

问题的求解实际上就是在这个图中找到一条路径可以从开始到结果。

这个寻找的过程就是状态空间搜索。

常用的状态空间搜索有深度优先和广度优先。

广度优先是从初始状态一层一层向下找,直到找到目标为止。

深度优先是按照一定的顺序,先查找完一个分支,再查找另一个分支,直至找到目标为止。

这两种算法在数据结构书中都有描述,可以参看这些书得到更详细的解释。

前面说的广度和深度优先搜索有一个很大的缺陷就是:他们都是在一个给定的状态空间中穷举。

这在状态空间不大的情况下是很合适的算法,可是当状态空间十分大,且不可预测的情况下就不可取了。

他们的效率实在太低,甚至不可完成。

在这里就要用到启发式搜索了。

启发式搜索就是在状态空间中搜索时,对每一个搜索的位置进行评估,得到最好的位置,再从这个位置进行搜索直至找到目标。

这样可以省略大量无谓的搜索路径,提高了效率。

在启发式搜索中,对位置的估价是十分重要的。

采用了不同的估价可以有不同的效果。

我们先看看估价是如何表示的。

启发中的估价是用估价函数表示的,如:f(n) = g(n) + h(n)其中f(n)是节点n的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n节点到目标节点最佳路径的估计代价。

在这里主要是h(n)体现了搜索的启发信息,因为g(n)是已知的。

最优路径问题的启发式搜索算法

最优路径问题的启发式搜索算法

最优路径问题的启发式搜索算法启发式搜索算法是一种常用的优化算法,广泛应用于求解最优路径问题。

最优路径问题是指在给定的图中,寻找两个节点之间的最短路径或最优路径。

启发式搜索算法通过引入启发函数,对搜索过程进行优化,以提高搜索效率。

一、问题描述最优路径问题可以用图表示,图由节点和边组成。

节点表示位置或状态,边表示两个节点之间的关系或连接。

给定一个起始节点和目标节点,最优路径问题的目标是找到从起始节点到目标节点的最短路径或最优路径。

二、传统的搜索算法传统的搜索算法包括深度优先搜索(DFS)和广度优先搜索(BFS)。

DFS从起始节点开始,沿着每条可能的路径一直搜索到目标节点或无法继续搜索为止。

BFS则按层次遍历的方式,先搜索起始节点所有邻接节点,然后依次搜索这些邻接节点的邻接节点,直到找到目标节点。

传统的搜索算法存在效率低下的问题。

DFS通常能够找到一条路径,但该路径未必是最短路径或最优路径。

而BFS虽然能够找到最短路径,但在搜索过程中需要存储和遍历大量的节点,导致计算成本高。

三、启发式搜索算法启发式搜索算法引入了启发函数,用于评估搜索过程中每个节点的价值或成本。

启发函数通常根据问题的特定性质和经验进行设计,可以根据启发函数的值对节点进行评估和排序。

基于启发函数的评估,启发式搜索算法能够优先考虑具有更高潜在价值的节点,提高搜索效率。

最著名的启发式搜索算法之一是A*算法。

A*算法综合考虑了两个因素:从起始节点到当前节点的实际路径成本(表示为g值),以及从当前节点到目标节点的预估路径成本(表示为h值)。

A*算法通过计算启发函数值f = g + h,来评估节点的价值,从而选择具有最小f值的节点进行搜索。

A*算法在搜索过程中通过维护一个优先队列,不断扩展距离起始节点较好的节点,直到找到目标节点或搜索完成。

四、应用实例启发式搜索算法在许多领域都有应用,其中最著名的例子之一就是在计算机游戏中的路径规划。

在游戏中,启发式搜索算法能够帮助角色或NPC找到最短路径或最优路径,以避开障碍物或敌人。

搜索策略实验

搜索策略实验

实验一:搜索策略实验一、实验目的1、熟悉和掌握启发式搜索的定义、估价函数和算法过程。

2、利用A*算法求解N数码难题,理解求解流程和搜索顺序。

二、实验内容以八数码为例实现A或A*算法。

1、分析算法中的OPEN表CLOSE表的生成过程。

2、分析估价函数对搜索算法的影响。

3、分析启发式搜索算法的特点。

起始棋局目标棋局启发式函数选取为:f*(n)=g*(n)+h*(n)其中:g*(n)是搜索树中节点n的深度;h*(n)用来计算对应于节点n的数据中错放的棋子个数。

三、实验设计与结果八数码问题是个典型的状态图搜索问题。

搜索方式有两种基本的方式,即树式搜索和线式搜索。

搜索策略大体有盲目搜索和启发式搜索两大类。

盲目搜索就是无“向导”的搜索,启发式搜索就是有“向导”的搜索。

由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零。

所以,这个数码不同的位置个数便是标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息就可以指导搜索。

即可以利用启发信息来扩展节点的选择,减少搜索范围,提高搜索速度。

由此解决八数码问题就是在初始状态和目标状态两个状态之间寻找一系列可过渡状态。

利用A*算法实现寻找中间状态,从而得到目标状态。

根据启发式搜索算法A*算法的具体步骤,结合八数码问题的要求,从而得出相应的流程图为:其中:OPEN表:算法已搜索但尚未扩展的节点集合。

CLOSED表:算法已扩展的节点集合。

实验输出结果:运行程序,输入起始棋局与目标棋局:结果输出为:四、程序1、设定启发式函数:八数码问题的目标是要搜索到目标节点,所以为了尽快的向目标节点进行靠近,可以把启发式函数设定为当前节点与目标节点中状态的差异,即与目标节点中数码的位置不同的个数作为启发函数的返回值,然后根据启发函数值找出启发值最小的状态节点进行扩展。

2、OPEN表和CLOSE表的生成过程:OPEN表是用来存放经过扩展得到的待考察的状态节点,CLOSE表是用来存放考察过的状态节点,并且标记上当前节点的编号和父节点的编号,然后可以根据编号便可以形成一个搜索树,即可以找到一个解路径。

实验一启发式搜索

实验一启发式搜索

2. 启发式搜索过程的特性
(3)信息性
比较两个启发策略h1和h2,如果对搜索空间中的任何一个状态n都有h1(n) ≤h2(n),就说h2比h1具有更多的信息 性。 一般而言,若搜索策略h2比h1有更多的信息性,则h2比h1考察的状态要少。但必须注意的是更多信息性需 要更多的计算时间,从而有可能抵消减少搜索空间所带来的益处。
谢谢大家
12.06.2021
生产计划部
在一个限定的环境下,瞎子爬山法可能会极大的提高搜索的效率,但是对整个搜索空间而言,可能 得不到全局最优解。
(2)最好优先搜索法(有序搜索法)
该算法的估价函数采用f(n) = g(n) + h(n),在搜索过程中算法使用OPEN表和CLOSE表来记录节点信息: OPEN表中保留所有已生成而未考察的节点;CLOSE表中保留所有已访问过的节点。算法在每一次搜索过 程中都会对OPEN表中的节点按照每个节点的f值进行排序,选择f值最小节点进行扩展。
实验一启发式搜索
12.06.2021
生产计划部
一、实验目的:
熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A算法求解九宫问题,理解求解流程 和搜索顺序。
二、实验方法:
• 1.先熟悉启发式搜索算法; • 2.用C、C++或JAVA 语言编程实现实验内容。
三、实验背景知识
1.估价函数 在对问题的状态空间进行搜索时,为提高搜索效率需要和被解问题的解有关的大量控制性知识作为搜索的辅 助性策略。这些控制信息反映在估价函数中。 估价函数的任务就是估计待搜索节点的重要程度,给这些节点排定次序。估价函数可以是任意一种函数,如 有的定义它是节点x处于最佳路径的概率上,或是x节点和目标节点之间的距离等等。在此,我们把估价函数 f(n)定义为从初始节点经过n节点到达目标节点的最小代价路径的代价估计值,它的一般形式是: f(n) = g(n) + h(n) 其中g(n)是从初始节点到节点n的实际代价,g(n)可以根据生成的搜索树实际计算出来;h(n)是从n到目标节点 的最佳路径的代价估计,h(n)主要体现了搜索的启发信息。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验一启发式搜索算法学号:**********班级:计科二班姓名:***一、实验内容:使用启发式搜索算法求解8数码问题。

1、编制程序实现求解8数码问题A *算法,采用估价函数()()()()w n f n d n p n ⎧⎪=+⎨⎪⎩, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。

2、 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界 的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。

二、实验目的:熟练掌握启发式搜索A *算法及其可采纳性。

三、实验原理:(一)问题描述在一个3*3的方棋盘上放置着1,2,3,4,5,6,7,8八个数码,每个数码占一格,且有一个空格。

这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。

现在的问题是:对于指定的初始棋局和目标棋局,给出数码的移动序列。

该问题称八数码难题或者重排九宫问题。

(二)问题分析八数码问题是个典型的状态图搜索问题。

搜索方式有两种基本的方式,即树式搜索和线式搜索。

搜索策略大体有盲目搜索和启发式搜索两大类。

盲目搜索就是无“向导”的搜索,启发式搜索就是有“向导”的搜索。

启发式搜索:由于时间和空间资源的限制,穷举法只能解决一些状态空间很小的简单问题,而对于那些大状态空间的问题,穷举法就不能胜任,往往会导致“组合爆炸”。

所以引入启发式搜索策略。

启发式搜索就是利用启发性信息进行制导的搜索。

它有利于快速找到问题的解。

由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零。

所以,这个数码不同的位置个数便是标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息就可以指导搜索。

即可以利用启发信息来扩展节点的选择,减少搜索范围,提高搜索速度。

启发函数设定。

对于八数码问题,可以利用棋局差距作为一个度量。

搜索过程中,差距会逐渐减少,最终为零,为零即搜索完成,得到目标棋局。

四、实验程序及其说明:1)int goal[N][N],struct Chessboard :试验中我定义goal 数组为目标状态——{1,2,3,8,0,4,7,6,5}。

结构体Chessboard 记录棋盘信息,其中变量pos 数组坐标记录每个数码a 的位置,其值为数码a 。

d 表示该棋盘的深度,f 为启发函数值,move 为父节点移动到该节点的方式,以便在输出时告诉用户该如何移动棋子知道目标状态。

2)struct LNode :定义节点LNode 结构体,存放该节点状态时的棋盘信息board ,和指向父节点、下一节点的指针(*parent,*next),以及标记量flag ——值为true 时表示该节点是最佳路径上的节点。

3)int* Findzero(LNode* &Node):为方便找到空格,我设计了找到该函数Findzero(*&Node),以便找到当前节点空格所在位置以利于接下来的程序执行。

返回值为空格所在的行和列。

4)int Wrong(LNode *Node)和int pick(LNode *Node):分别为函数)(n ω和)(n p 。

5)LNode* extend(LNode *Node,int depth,int zero[2],int moveflag,int Choose)树形方式扩展节点。

Node 为要扩展的当前节点,depth 为当前深度,zero 存放该节点空格位置信息,moveflag 即扩展节点的移动方式,Choose 为选择函数)(n ω还是)(n p 。

6)void InitList(LNode* &Open,LNode* &Close)和int ListInsert(List &L,LNode* NewNode)分别为表OPEN 、CLOSE 的创建和表的插入操作。

7)LNode* Getminf(List &L)主要是实现从OPEN 表中选择一个f 值最小的节点i 。

如果有几个节点值相同,当其中 有一个为目标节点时,则选择此目标节点;否则就选择其中任一个节点作为节点i 。

五、实验源代码#include<stdio.h>#include<malloc.h>#include<stdlib.h>#define Overflow 1#define N 3int goal[N][N]={1,2,3,8,0,4,7,6,5};int zero[2],NodeQTY=0;int *z=zero;//记录0的位置,zero[0]:r 行;zero[1]:c 列typedef int Piece;struct Chessboard{//棋盘信息Piece pos[N][N];//记录每个数码a的位置r行c列int d,f,move;//d:深度;f:启发函数值;move:父节点移动到该节点的方式};struct LNode{Chessboard board;LNode *parent,*next;bool flag;};typedef LNode* List;int* Findzero(LNode* &Node){int i,j,zr[2];int *z=zr;for(i=0;i<N;i++){for(j=0;j<N;j++){if(Node->board.pos[i][j]==0){zr[0]=i+1;zr[1]=j+1;break;}}}return z;}int Wrong(LNode *Node){int w=0,i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(Node->board.pos[i][j]!=goal[i][j]&&Node->board.pos[i][j]!=0)w++;}}return w;}int pick(LNode *Node){int w=0,i,j,ii,jj;for(i=0;i<N;i++){for(j=0;j<N;j++){if(Node->board.pos[i][j]!=goal[i][j]&&Node->board.pos[i][j]!=0){ for(ii=0;ii<N;ii++)for(jj=0;jj<N;jj++)if(Node->board.pos[i][j]==goal[ii][jj]){w=w+abs(ii-i)+abs(jj-j);break;}}}}return w;}LNode* extend(LNode *Node,int depth,int zero[2],int moveflag,int Choose){LNode* NewNode=new LNode;for(int i=0;i<N;i++){for(int j=0;j<N;j++){NewNode->board.pos[i][j]=Node->board.pos[i][j];}}switch(moveflag){case 1: //向左移,不能出界:zero[1]>=2New-Node->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]-1][zero[1]-2];NewNode->board.pos[zero[0]-1][zero[1]-2]=0;break;case 2: //向右移,不能出界:zero[1]<=2New-Node->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]-1][zero[1]];NewNode->board.pos[zero[0]-1][zero[1]]=0;break;case 3: //向上移,不能出界:zero[0]>=2New-Node->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]-2][zero[1]-1];NewNode->board.pos[zero[0]-2][zero[1]-1]=0;break;case 4: //向下移,不能出界:zero[0]<=2New-Node->board.pos[zero[0]-1][zero[1]-1]=NewNode->board.pos[zero[0]][zero[1]-1];NewNode->board.pos[zero[0]][zero[1]-1]=0;break;}NewNode->board.d=depth+1;switch(Choose){case 1:NewNode->board.f=NewNode->board.d+Wrong(NewNode);break;case 2:NewNode->board.f=NewNode->board.d+pick(NewNode);break;}NewNode->board.move=moveflag;NewNode->parent=Node;NodeQTY++;return NewNode;}void InitList(LNode* &Open,LNode* &Close){Open=(List)malloc(sizeof(LNode));Close=(List)malloc(sizeof(LNode));if(!Open&&!Close)exit(Overflow);Open->next=NULL;Close->next=NULL;}int ListInsert(List &L,LNode* NewNode){List p=L;while(p->next){p=p->next;}NewNode->next=p->next;p->next=NewNode;return true;}LNode* Getminf(List &L){List p=L,q=L->next,r=L,min;min=q;//p,q寻找f最小值的指针,r指向表L中min前一个元素if(!q)return NULL;while(q){if(min->board.f>q->board.f){r=p;min=q;}p=q;q=q->next;}r->next=min->next;min->next=NULL;return min;}int main(){int i,j,choose;List Open,Close;LNode *Best,*current;LNode *Start=new LNode;printf("\t\t\t八数码问题求解\n");printf("\n请输入初始状态:");for(i=0;i<N;i++){for(j=0;j<N;j++){scanf("%d",&(Start->board.pos[i][j]));}}printf("(注:The flag of movement--1:左移;2:右移;3:上移;4:下移)\n"); printf("初始棋盘状态:\n");for(i=0;i<N;i++){for(j=0;j<N;j++){printf("|%d",Start->board.pos[i][j]);}printf("|\n");}InitList(Open,Close);printf("请选择(1:A算法;2:A*算法):");scanf("%d",&choose);Start->board.d=0;switch(choose){case 1:Start->board.f=Start->board.d+Wrong(Start);break;case 2:Start->board.f=Start->board.d+pick(Start);break;} // Start->board.f=0+Wrong(Start);Start->board.move=0;Start->parent=NULL;Start->next=NULL;Start->flag=1;ListInsert(Open,Start);//将S加入到Open表中while(Open->next){Best=Getminf(Open);ListInsert(Close,Best);if(!(Best->board.f-Best->board.d)){printf("$$$******有解!******$$$\n");break;}z=Findzero(Best);zero[0]=*(z+0);zero[1]=*(z+1);if(zero[1]>=N-1&&Best->board.move!=2)ListInsert(Open,extend(Best,Best->board.d,zero,1,choose));if(zero[1]<=N-1&&Best->board.move!=1)ListInsert(Open,extend(Best,Best->board.d,zero,2,choose));if(zero[0]>=N-1&&Best->board.move!=4)ListInsert(Open,extend(Best,Best->board.d,zero,3,choose));if(zero[0]<=N-1&&Best->board.move!=3)ListInsert(Open,extend(Best,Best->board.d,zero,4,choose));}printf("本算法搜索图中总共扩展的节点数为:%d\n",NodeQTY);printf("\t最佳路径如下所示:\n");if(Open->next){while(Best->parent){Best->flag=1;Best=Best->parent;}List p=Close->next,q=Close->next;if(p==Start) q=p->next;else exit(1);int Step=0;while(p&&q)//在Close表中依标记找到路径{if(q->flag==1&&q->parent==p){printf("Step %d:0 move asthe %d-flag of movement.\n",++Step,q->board.move);for(i=0;i<N;i++){for(j=0;j<N;j++){printf("|%d",q->board.pos[i][j]);}printf("|\n");}p=q;//记住父节点}q=q->next;}printf("到达目标状态!\n");}else printf("该问题无法求解!\n");}六、实验总结通过本次实验,让我更加了解启发式搜索算法的原理,见识了其广泛的应用;同时加强了本人阅读程序能力和编程能力,以及如何将理论问题解决实际应用的能力。

相关文档
最新文档