启发式搜索实验报告
2014-人工智能应用技术实验报告-启发式搜索程序设计
实验报告课程名称人工智能应用技术实验项目启发式搜索程序设计实验仪器Windows/VisualStudio学院信息管理学院专业信息安全班级/学号信安1401/学生姓名Cony实验日期2016-5-17成绩指导教师赵刚北京信息科技大学信息管理学院(课程上机)实验报告5.实验过程:#include<stdio.h>#include<malloc.h>#include<assert.h>//#include "rand.h"#include<stdlib.h>#include<time.h>#define RANDINIT() srand(time(NULL))#define RANDOM() ((float)rand() / (float)RAND_MAX)#define RANDMAX(x) (int)((float)(x)*rand()/(RAND_MAX+1.0))#define MAX_BOARD9#define ALPHA(double)1.0 /* Depth Bias */#define BETA(double)2.0 /* Misplaced Tile Bias */#define MAX_DEPTH26struct board_s;typedef struct board_s {struct board_s *pred;double f;double g;double h;char array[MAX_BOARD];char blank;char depth;} board_t;/* Node Functions */board_t *nodeAlloc( void ){board_t *board_p;board_p = (board_t *)malloc( sizeof(board_t) );assert(board_p);board_p->pred = NULL;board_p->f = board_p->g = board_p->h = (double)0.0;return board_p;}void nodeFree( board_t *board_p ){assert(board_p);free(board_p);return;}/* List Functions */#define MAX_LIST_ELEMENTS100000typedef struct {int numElements;board_t *elements[MAX_LIST_ELEMENTS];} list_t;#define listCount(x) ((x)->numElements)list_t openList_p;list_t closedList_p;void initList( list_t *list_p ){int i;assert(list_p);list_p->numElements = 0;for (i = 0 ; i < MAX_LIST_ELEMENTS ; i++) { list_p->elements[i] = (board_t *)0;}return;}int onList( list_t *list_p, char *board_p, int *pos ) {int i, j;assert(list_p); assert(board_p);for (i = 0 ; i < MAX_LIST_ELEMENTS ; i++) {if (list_p->elements[i] != (board_t *)0) {for (j = 0 ; j < MAX_BOARD ; j++) {if (list_p->elements[i]->array[j] != board_p[j]) break; }if (j == MAX_BOARD) {if (pos) *pos = i;return 1;}}}return 0;}board_t *getListBest( list_t *list_p ){int i, first=1;int best=-1;double best_f;board_t *board_p;for (i = 0 ; i < MAX_LIST_ELEMENTS ; i++) {if (list_p->elements[i]) {if (first) {best = i;best_f = list_p->elements[best]->f;first = 0;} else {if (list_p->elements[i]->f < best_f) {best = i;best_f = list_p->elements[best]->f;}}}}assert( best != -1 );board_p = list_p->elements[best];list_p->elements[best] = (board_t *)0;list_p->numElements--;return board_p;}board_t *getList( list_t *list_p, char *board_p ) {int pos, ret;board_t *retboard_p = (board_t *)0;assert(list_p); assert(board_p);ret = onList( list_p, board_p, &pos );if (ret) {retboard_p = list_p->elements[pos];list_p->elements[pos] = (board_t *)0;list_p->numElements--;}return retboard_p;}void putList( list_t *list_p, board_t *board_p ) {int i;assert(list_p); assert(board_p);for (i = 0 ; i < MAX_LIST_ELEMENTS ; i++) {if (list_p->elements[i] == (board_t *)0) {list_p->elements[i] = board_p;list_p->numElements++;return;}}assert(0);}void cleanupList( list_t *list_p ){int i;assert(list_p);for (i = 0 ; i < MAX_LIST_ELEMENTS ; i++) {if (list_p->elements[i] != (board_t *)0) {nodeFree(list_p->elements[i]);list_p->numElements--;}}return;}double evaluateBoard( board_t *board_p ){int i;const int test[MAX_BOARD-1]={1, 2, 3, 4, 5, 6, 7, 8 };int score=0;for (i = 0 ; i < MAX_BOARD-1 ; i++) {score += (board_p->array[i] != test[i]); }return (double)score;}int countInversions( char *array ){int i, j, inversions = 0;for (j = 0 ; j < MAX_BOARD-1 ; j++) {for (i = j+1 ; i < MAX_BOARD ; i++) {if (array[j] > array[i]) inversions++;}}return inversions;}board_t *initPuzzle( void ){int i, inversions;board_t *board_p;board_p = nodeAlloc();for (i = 0 ; i < MAX_BOARD-1 ; i++) {board_p->array[i] = i+1;}board_p->array[i] = 0;do {/* Randomize the board */for (i = 0 ; i < MAX_BOARD ; i++) {int x = RANDMAX(MAX_BOARD);int y = RANDMAX(MAX_BOARD);int temp = board_p->array[x];board_p->array[x] = board_p->array[y];board_p->array[y] = temp;}inversions = countInversions( board_p->array ); } while (inversions & 1);/* Find the blank space (we need to track it) */for (i = 0 ; i < MAX_BOARD ; i++) {if (board_p->array[i] == 0) {board_p->blank = i;break;}}board_p->f = board_p->h = evaluateBoard( board_p );/* Depth is zero -- top of the tree */board_p->depth = 0;return board_p;}void emitPuzzleBoard( board_t *board ){int i;assert(board);for (i = 0 ; i < MAX_BOARD ; i++) {if ((i%3) == 0) printf("\n");if (board->array[i] == 0) printf(" ");else printf("%c", 'A'+board->array[i]-1);}printf("\n");return;}#define MAX_VECTOR 4typedef struct {unsigned int len;unsigned int vector[MAX_VECTOR];} move_t;const move_t moves[MAX_BOARD] = {/* 0 */ { 2, {1, 3} },/* 1 */ { 3, {0, 2, 4} },/* 2 */ { 2, {1, 5} },/* 3 */ { 3, {0, 4, 6} },/* 4 */ { 4, {1, 3, 5, 7} },/* 5 */ { 3, {2, 4, 8} },/* 6 */ { 2, {3, 7} },/* 7 */ { 3, {4, 6, 8} },/* 8 */ { 2, {5, 7} } };board_t *getChildBoard( board_t *board_p, int index ){board_t *child_p = (board_t *)0;int blankSpot;int i;blankSpot = board_p->blank;if (index < moves[blankSpot].len) {int moveFrom;child_p = nodeAlloc();/* Copy board from parent to child */for (i = 0 ; i < MAX_BOARD ; i++) {child_p->array[i] = board_p->array[i];}child_p->blank = board_p->blank;moveFrom = moves[blankSpot].vector[index];child_p->array[ (int)child_p->blank ] = child_p->array[ moveFrom ];child_p->array[ moveFrom ] = 0;child_p->blank = moveFrom;}return child_p;}void showSolution( board_t *goal ){board_t *revList[MAX_LIST_ELEMENTS];int i = 0, j;printf("Solution:\n");while (goal) {revList[i++] = goal;goal = goal->pred;}for (j = i-1 ; j >= 0 ; j--) {emitPuzzleBoard( revList[j] );printf("\n");}return;}void astar( void ){board_t *cur_board_p, *child_p, *temp;int i;/* While items are on the open list */while ( listCount(&openList_p) ) {/* Get the current best board on the open list */ cur_board_p = getListBest( &openList_p );putList( &closedList_p, cur_board_p );/* Do we have a solution? */if (cur_board_p->h == (double)0.0) {showSolution( cur_board_p );return;} else {/* Heuristic - average number of steps is 22 for a 3x3, so don't go * too deep.*/if (cur_board_p->depth > MAX_DEPTH) continue;/* Enumerate adjacent states */for (i = 0 ; i < 4 ; i++) {child_p = getChildBoard( cur_board_p, i );if (child_p != (board_t *)0) {if ( onList(&closedList_p, child_p->array, NULL) ) {nodeFree( child_p );continue;}child_p->depth = cur_board_p->depth + 1;child_p->h = evaluateBoard( child_p );child_p->g = (double)child_p->depth;child_p->f = (child_p->g * ALPHA) + (child_p->h * BETA);/* New child board on the open list? */if ( onList(&openList_p, child_p->array, NULL) ) {assert( !onList(&closedList_p, child_p->array, NULL) );temp = getList(&openList_p, child_p->array);if (temp->g < child_p->g) {nodeFree(child_p);putList(&openList_p, temp);continue;}nodeFree( temp );} else {/* Child board either doesn't exist, or is better than a * previous board. Hook it to the parent and place on the * open list.*/child_p->pred = cur_board_p;putList( &openList_p, child_p );}}}}}return;}int main(){board_t *initial_p;RANDINIT();initList( &openList_p );initList( &closedList_p );initial_p = initPuzzle();putList( &openList_p, initial_p );astar();1.实验名称、实验目的、实验内容、实验要求由教师确定,实验前由教师事先填好,然后作为实验报告模版供学生使用;2.实验准备由学生在实验或上机之前填写,教师应该在实验前检查;3.实验过程由学生记录实验的过程,包括操作过程、遇到哪些问题以及如何解决等;4.实验总结由学生在实验后填写,总结本次实验的收获、未解决的问题以及体会和建议等;5.源程序、代码、具体语句等,若表格空间不足时可作为附录另外附页。
人工智能实验报告
人工智能实验报告实验一 在搜索策略实验群实验目的熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解N 数码难题,理解求解流程和搜索顺序。
搜索图算法比较广度优先深度优先 A*Open 表 节点G ,节点10节点G ,节点6节点3,节点9,节点G ,节点10,节点8Close 表节点s ,节点1,节点2,节点3,节点4,节点5,节点6,节点7,节点8,节点9 节点s,节点1,节点3,节点7,节点4,节点8,节点2,节点5,节点9节点s ,节点2,节点1,节点5,节点6,节点4估价函数无无)()()(n h n g n f +=搜索节点次序记录 节点s ,节点1,节点2,节点3,节点4,节点5,节点6,节点7,节点8,节点9,节点G 节点s,节点1,节点3,节点7,节点4,节点8,节点2,节点5,节点9,节点G 节点s ,节点2,节点1,节点5,节点6,节点4,节点G观测结果 经过11步搜索得到目标节点经过10步搜索得到目标节点经过7步搜索得到目标节点学生结论宽度优先搜索能保证在搜索树 深度优先搜索要沿路径一条一 A*算法是启发式算法的一中找到一条通向目标节点的最短路径,但由于盲目性大所以当搜索数据比较多的时候该方法较为费时。
条的走到底,如果目标在前几条路径中那么该搜索会较为快捷,在本搜索树中虽然比宽度优先少一步,但是若第一条路径或者某几条路径很深,则该搜索会相当耗时且不能保证成功。
种能通过路径的权值找出代价最为小的一条,所以很具优越性,但是算法本身计算较为复杂,要考虑以前的和将来两方面的代价,进行估算,所以没有前两种方法简单。
实验二:产生式系统实验实验目的熟悉和掌握产生式系统的运行机制,掌握基于规则推理的基本方法。
推理方法□ 正向推理 □ 反向推理建立规则库 建立事实库该动物是哺乳动物 <- 该动物有毛发. 该动物是哺乳动物 <- 该动物有奶.该动物是鸟 <- 该动物有羽毛.该动物是鸟 <- 该动物会飞&会下蛋. 该动物是食肉动物 <- 该动物吃肉.该动物是食肉动物 <- 该动物有犬齿&有爪&眼盯前方. 该动物是有蹄类动物 <- 该动物是哺乳动物&有蹄. 该动物是有蹄类动物 <- 该动物是哺乳动物& 是嚼反刍动物.该动物是金钱豹 <- 该动物是哺乳动物&是食肉动物&是黄褐色&身上有暗斑点.该动物是虎 <- 该动物是哺乳动物&是食肉动物&是黄褐色&身上有黑色条纹.该动物是长颈鹿 <- 该动物是有蹄类动物&有长脖子&有长腿&身上有暗斑点.该动物是斑马 <- 该动物是有蹄类动物&身上有黑色条纹.该动物是鸵鸟 <- 该动物是鸟&有长脖子&有长腿&不会飞&有黑白二色.该动物是企鹅 <- 该动物是鸟&会游泳&不会飞&有黑白二色.该动物是信天翁 <- 该动物是鸟&善飞.%------动物识别系统事实集: %--该动物是企鹅 会游泳. 不会飞.有黑白二色. %该动物是鸟.%-------- %--该动物是鸟 该动物会飞.会下蛋.%----该动物是金钱豹 <- 该动物是哺乳动物&是食肉动物&是黄褐色&身上有暗斑点. 该动物有毛发. %是食肉动物. 是黄褐色. 身上有暗斑点. 该动物吃肉.%----该动物是虎 <- 该动物是哺乳动物&是食肉动物&是黄褐色&身上有黑色条纹.该动物是哺乳动物.%是食肉动物. 是黄褐色.身上有黑色条纹.%----该动物是长颈鹿 <- 该动物是有蹄类动物&有长脖子&有长腿&身上有暗斑点. %该动物是有蹄类动物. 有长脖子. 有长腿. 身上有暗斑点.%----该动物是有蹄类动物 <- 该动物是哺乳动物&有蹄. %有蹄.预测结果在相关询问:该动物是哺乳动物? 该动物是鸟? 该动物是食肉动物? 该动物是金钱豹?该动物是鸵鸟?该动物是企鹅?时为真,其余为假。
基于启发式搜索算法A星解决八数码问题
int statue[size][size]; //记录当前节点的状态 struct Node * Tparent; //用来构成搜索树,该树由搜索图的反向指针构成 struct Node * opennext; //用来构成 open 表,该指针指向该节点在 open 表中的下一个 节点 struct Node * closenext; //用来构成 open 表,该指针指向该节点在 close 表中的下一个 节点 struct Node * brothernext; //构成兄弟链表,该指针指向该节点在兄弟链表中的下一个节 点 int f; //记录当前节点的 f 函数值 int g; //记录当前节点的 g 函数的值 int h; //记录当前节点的 h 函数的值 };
5
get_bestroute (bestNode); return; }
2.2.7 生成 bestNode 所指节点的后继节点
定义一个后继节点链表,表头为 head_b,将 bestNode 所指节点的不是前驱节点的后继 节点,链接到后继及诶单链表中。getchild 函数可以实现这个功能。
//产生 bestNode 的一切后继节点。。 head head_b; //定义 bestNode 的后继节点表 head_b.next=NULL; getchild (&head_b,bestNode); //产生 bestNode 的子节点,将不是 bestNode 的父节点的
while (head_b.next!=NULL) { Node *tmp=getbrother (&head_b); //从后继节点表中取出一个节点记为 tmp,并从
实验一 启发式搜索算法
实验一启发式搜索算法学号:**********班级:计科二班姓名:***一、实验内容:使用启发式搜索算法求解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八个数码,每个数码占一格,且有一个空格。
这些数码可以在棋盘上移动,其移动规则是:与空格相邻的数码方格可以移入空格。
现在的问题是:对于指定的初始棋局和目标棋局,给出数码的移动序列。
该问题称八数码难题或者重排九宫问题。
(二)问题分析八数码问题是个典型的状态图搜索问题。
搜索方式有两种基本的方式,即树式搜索和线式搜索。
搜索策略大体有盲目搜索和启发式搜索两大类。
盲目搜索就是无“向导”的搜索,启发式搜索就是有“向导”的搜索。
启发式搜索:由于时间和空间资源的限制,穷举法只能解决一些状态空间很小的简单问题,而对于那些大状态空间的问题,穷举法就不能胜任,往往会导致“组合爆炸”。
所以引入启发式搜索策略。
启发式搜索就是利用启发性信息进行制导的搜索。
它有利于快速找到问题的解。
由八数码问题的部分状态图可以看出,从初始节点开始,在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零。
所以,这个数码不同的位置个数便是标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息就可以指导搜索。
即可以利用启发信息来扩展节点的选择,减少搜索范围,提高搜索速度。
a算法求解八数码问题 实验报告
题目: a算法求解八数码问题实验报告目录1. 实验目的2. 实验设计3. 实验过程4. 实验结果5. 实验分析6. 实验总结1. 实验目的本实验旨在通过实验验证a算法在求解八数码问题时的效果,并对其进行分析和总结。
2. 实验设计a算法是一种启发式搜索算法,主要用于在图形搜索和有向图中找到最短路径。
在本实验中,我们将使用a算法来解决八数码问题,即在3x3的九宫格中,给定一个初始状态和一个目标状态,通过移动数字的方式将初始状态转变为目标状态。
具体的实验设计如下:1) 实验工具:我们将使用编程语言来实现a算法,并结合九宫格的数据结构来解决八数码问题。
2) 实验流程:我们将设计一个初始状态和一个目标状态,然后通过a 算法来求解初始状态到目标状态的最短路径。
在求解的过程中,我们将记录下每一步的状态变化和移动路径。
3. 实验过程我们在编程语言中实现了a算法,并用于求解八数码问题。
具体的实验过程如下:1) 初始状态和目标状态的设计:我们设计了一个初始状态和一个目标状态,分别为:初始状态:1 2 34 5 67 8 0目标状态:1 2 38 0 42) a算法求解:我们通过a算法来求解初始状态到目标状态的最短路径,并记录下每一步的状态变化和移动路径。
3) 实验结果在实验中,我们成功求解出了初始状态到目标状态的最短路径,并记录下了每一步的状态变化和移动路径。
具体的实验结果如下:初始状态:1 2 34 5 67 8 0目标状态:1 2 38 0 47 6 5求解路径:1. 上移1 2 37 8 62. 左移1 2 3 4 0 5 7 8 63. 下移1 2 3 4 8 5 7 0 64. 右移1 2 3 4 8 5 0 7 65. 上移1 2 3 0 8 5 4 7 61 2 38 0 54 7 67. 下移1 2 38 7 54 0 68. 右移1 2 38 7 54 6 0共计8步,成功从初始状态到目标状态的最短路径。
启发式搜索实验
.
z.
-
// 起始节点经过*个节点到目的节点的距离
int[][] HList = null;
/**Biblioteka * 构造函数** param maze
*
迷宫图
* param startPoint
*
起始节点
* param endPoint
*
完毕节点
*/
public It**zAstar(Point[][] mazePoint, Point startPoint, Point endPoint) {
.
z.
-
for (int i = 0; i < mazePoint.length; i++) { for (int j = 0; j < mazePoint[0].length; j++) { FList[i][j] = Integer.MA*_VALUE; GList[i][j] = Integer.MA*_VALUE; HList[i][j] = Integer.MA*_VALUE; }
} // 起始节点到当前节点的距离 GList[startPoint.get*()][startPoint.getY()] = 0; // 当前节点到目的节点的距离 HList[startPoint.get*()][startPoint.getY()] = getPointDistance(
startPoint.get*(), startPoint.getY(), endPoint.get*(), endPoint.getY()); // f(*) = g(*) + h(*) FList[startPoint.get*()][startPoint.getY()] = GList[startPoint.get*()][startPoint .getY()] + HList[startPoint.get*()][startPoint.getY()]; } /** * 计算当前坐标与完毕坐标之间的距离 * * 计算方法为每向相信坐标移动一次算作一个距离单位 *
人工智能概论-搜索算法编程及实验报告
人工智能概论大作业学院:电子工程学院专业:智能科学与技术题目一:搜索算法编程及实验报告一.算法题目八数码难题的求解。
二.实验目的从盲目搜索和启发式搜索方法中分别选择一种解决八数码难题,给出搜索树和从起始节点到目标节点的路径。
三.实验设备及软件环境Win7的笔记本电脑,VS2013(使用c语言编程)。
四.实验方法1.盲目搜索——宽度优先搜索。
(1).算法描述如果搜索是以接近其实节点的程度来依次扩展节点,那么这中搜索就叫宽度优先搜索。
这种搜索是逐层进行的,在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点。
(1)把起始节点放到OPEN表中(如果该起始节点为一目标节点,则求得一个解答)。
(2)如果OPEN是个空表,则没有解,失败退出;否则继续。
(3)把第一个节点(节点 n)从OPEN表移出,并把它放入CLOSED扩展节点表中。
(4)扩展节点n。
如果没有后继节点,则转向上述第(2)步。
(5)把n 的所有后继节点放到OPEN表的末端,并提供从这些后继节点回到n的指针。
(6)如果n 的任一个后继节点是个目标节点,则找到一个解答,成功退出;否则转向第(2)步。
(2).算法流程图(3).程序代码#include "stdio.h"#include "conio.h"#include "string.h" struct pic{char data[10];char imoperate;int father;char extend; };char end[10] = "1238 4765";int result[100];int n;int m;pic base[100];char *w;int find(int x){for (int i = 0; i < 10; i++)if (base[x].data[i] != end[i])return 0;return 1;}void showline(int x){int i = 0;while (base[x].father != -1){result[i] = x;x = base[x].father;i++;}result[i] = 0;result[i + 1] = '\0';m = i;printf("\n搜索路径");for (i = m; i >= 0; i--){printf("\n\n\n");printf("%c\t%c\t%c\n", base[result[i]].data[0], base[result[i]].data[1], base[result[i]].data[2]);printf("%c\t%c\t%c\n", base[result[i]].data[3], base[result[i]].data[4], base[result[i]].data[5]);printf("%c\t%c\t%c", base[result[i]].data[6], base[result[i]].data[7], base[result[i]].data[8]);}}int left(int x){int i;for (i = 0; i < 10; i++)if (base[x].data[i] == ' ')break;if (i == 0 || i == 3 || i == 6)return 0;for (int j = 0; j < 10; j++)base[n].data[j] = base[x].data[j];base[n].data[i] = base[x].data[i - 1];base[n].father = x;base[n].imoperate = 'R';base[n].extend = 'Y';base[x].extend = 'N';w = base[n].data;n++;if (find(n - 1) == 1)return 1;}int right(int x){int i;for (i = 0; i < 10; i++)if (base[x].data[i] == ' ')break;if (i == 2 || i == 5 || i == 8)return 0;for (int j = 0; j < 10; j++)base[n].data[j] = base[x].data[j];base[n].data[i + 1] = base[x].data[i];base[n].father = x;base[n].imoperate = 'L';base[n].extend = 'Y';base[x].extend = 'N';w = base[n].data;n++;if (find(n - 1) == 1)return 1;}int up(int x){int i;for (i = 0; i < 10; i++)if (base[x].data[i] == ' ')break;if (i == 0 || i == 1 || i == 2)return 0;for (int j = 0; j < 10; j++)base[n].data[j] = base[x].data[j];base[n].data[i - 3] = base[x].data[i];base[n].data[i] = base[x].data[i - 3];base[n].father = x;base[n].imoperate = 'D';base[n].extend = 'Y';base[x].extend = 'N';w = base[n].data;n++;if (find(n - 1) == 1)return 1;}int down(int x){int i;for (i = 0; i < 10; i++)if (base[x].data[i] ==' ')break;if (i == 6 || i == 7 || i == 8)return 0;for (int j = 0; j < 10; j++)base[n].data[j] = base[x].data[j];base[n].data[i + 3] = base[x].data[i];base[n].data[i] = base[x].data[i + 3];base[n].father = x;base[n].imoperate = 'U';base[n].extend = 'Y';base[x].extend = 'N';w = base[n].data;n++;if (find(n - 1) == 1)return 1;}void main(){void showtree(int x);n = 1;int i;strcpy_s(base[0].data, "2831 4765");base[0].imoperate = 'N';base[0].father = -1;base[0].extend = 'Y';for ( i = 0; i < 100; i++){if (base[i].extend == 'Y'){if (base[i].imoperate == 'L'){if (right(i) == 1)break;if (up(i) == 1)break;if (down(i) == 1)break;continue;}if (base[i].imoperate == 'R') {if (left(i) == 1)break;if (up(i) == 1)break;if (down(i) == 1)break;continue;}if (base[i].imoperate == 'U') {if (left(i) == 1)break;if (right(i) == 1)break;if (down(i) == 1)break;continue;}if (base[i].imoperate == 'D') {if (right(i) == 1)break;if (up(i) == 1)break;if (left(i) == 1)break;continue;}if (base[i].imoperate == 'N') {if (left(i) == 1)break;if (right(i) == 1)break;if (up(i) == 1)break;if (down(i) == 1)break;continue;}}}printf("搜索结束\n");showline(n - 1);showtree(n - 1);getchar();}void showtree(int x){printf("\n\n\n搜索树\n\n\n");int i;for (i = 0; i <= x; i++){if (i == 0){printf("\t\t\t %c%c%c\n", base[i].data[0], base[i].data[1], base[i].data[2]);printf("\t\t\t %c%c%c\n", base[i].data[3], base[i].data[4], base[i].data[5]);base[i].data[7], base[i].data[8]);printf("\t\t\t |\n");printf(" ");for (int j = 0; j < 49; j++)printf("-");printf("\n");printf(" |");printf(" |");printf(" |");printf(" |\n");continue;}if (i>0 && i <= 4){printf(" %c%c%c", base[i].data[0],base[i].data[1], base[i].data[2]);printf("\t %c%c%c", base[i+1].data[0], base[i+1].data[1], base[i+1].data[2]);printf("\t %c%c%c", base[i+2].data[0], base[i+2].data[1], base[i+2].data[2]);printf("\t %c%c%c\n", base[i+3].data[0], base[i+3].data[1], base[i+3].data[2]);printf(" %c%c%c", base[i].data[3],base[i].data[4], base[i].data[5]);base[i+1].data[4], base[i+1].data[5]);printf("\t %c%c%c", base[i+2].data[3], base[i+2].data[4], base[i+2].data[5]);printf("\t %c%c%c\n", base[i+3].data[3], base[i+3].data[4], base[i+3].data[5]);printf(" %c%c%c", base[i].data[6],base[i].data[7], base[i].data[8]);printf("\t %c%c%c", base[i+1].data[6], base[i+1].data[7], base[i+1].data[8]);printf("\t %c%c%c", base[i+2].data[6], base[i+2].data[7], base[i+2].data[8]);printf("\t %c%c%c\n", base[i+3].data[6], base[i+3].data[7], base[i+3].data[8]);printf(" |");printf(" |");printf(" |");printf(" |\n");printf(" ---------");printf(" ---------");printf(" ---------");printf(" ---------\n");printf(" | |");printf(" | |");printf(" | |");printf(" | |\n");i = 4;continue;}if (i > 4 && i <= 12){printf(" %c%c%c", base[i].data[0], base[i].data[1], base[i].data[2]);for (int j = 1; j < 8; j++)printf(" %c%c%c", base[i+j].data[0],base[i+j].data[1], base[i+j].data[2]);printf("\n %c%c%c", base[i].data[3],base[i].data[4], base[i].data[5]);for (int j = 1; j < 8; j++)printf(" %c%c%c", base[i + j].data[3], base[i + j].data[4], base[i + j].data[5]);printf("\n %c%c%c", base[i].data[6],base[i].data[7], base[i].data[8]);for (int j = 1; j < 8; j++)printf(" %c%c%c", base[i + j].data[6], base[i + j].data[7], base[i + j].data[8]);printf("\n | |");printf(" | |");printf(" | |");printf(" | |\n");i = 12;continue;}if (i > 12 && i <= 20){printf(" %c%c%c", base[i].data[0], base[i].data[1], base[i].data[2]);for (int j = 1; j < 8; j++)printf(" %c%c%c", base[i + j].data[0], base[i + j].data[1], base[i + j].data[2]);printf("\n %c%c%c", base[i].data[3],base[i].data[4], base[i].data[5]);for (int j = 1; j < 8; j++)printf(" %c%c%c", base[i + j].data[3], base[i + j].data[4], base[i + j].data[5]);printf("\n %c%c%c", base[i].data[6],base[i].data[7], base[i].data[8]);for (int j = 1; j < 8; j++)printf(" %c%c%c", base[i + j].data[6], base[i + j].data[7], base[i + j].data[8]);printf("\n | |");printf(" | |");printf(" | |");printf(" | |\n");printf(" -----");for (int j = 0; j < 7;j++)printf(" -----");printf("\n | |");for (int j = 0; j < 7; j++)printf(" | |");i = 20;continue;}if (i>20 && i <= 36){printf("\n%c%c%c", base[i].data[0], base[i].data[1], base[i].data[2]);for (int j = 1; j < 11; j++)printf(" %c%c%c", base[i + j].data[0], base[i + j].data[1], base[i + j].data[2]);printf("\n%c%c%c", base[i].data[3], base[i].data[4], base[i].data[5]);for (int j = 1; j < 11; j++)printf(" %c%c%c", base[i + j].data[3], base[i + j].data[4], base[i + j].data[5]);printf("\n%c%c%c", base[i].data[6], base[i].data[7], base[i].data[8]);for (int j = 1; j < 11; j++)printf(" %c%c%c", base[i + j].data[6], base[i + j].data[7], base[i + j].data[8]);i = 36;continue;}}}2.启发式搜索——有序搜索(1)算法描述有序搜索又称最好优先搜索,他总是选择最有希望的节点作为下一个要扩展的节点。
搜索策略实验
实验一:搜索策略实验一、实验目的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)主要体现了搜索的启发信息。
(完整版)启发式搜索算法
人工智能基础实验报告实验名称:八数码问题姓名:张俊学号:2220092333指导老师:邓安生启发式搜索算法1. 实验内容:使用启发式搜索算法求解8数码问题。
⑴ 编制程序实现求解8数码问题A *算法,采用估价函数()()()()w n f n d n p n ⎧⎪=+⎨⎪⎩, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。
⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。
2. 实验目的熟练掌握启发式搜索A *算法及其可采纳性。
3. 实验原理八数码问题是在3行和3列构成的九宫棋盘上放置数码为1到8的8个棋盘,剩下一个空格的移动来不断改变棋盘的布局,求解这类问题的方法是:给定初始布局(即初始状态)和目标布局(即目标状态),定义操作算子的直观方法是为每个棋牌制定一套可能的走步》上,下,左,右四种移动,再根据所定义的启发式搜索函数在搜索过程中选择最合适的操作算子,得到最优的路径。
4.源代码#include <iomanip>#include <stdlib.h>#include <time.h>#include <iostream>#include <stdio.h>#include <conio.h>#include <math.h>//以上为C++源文件using namespace std;static int space=0;int target[9];class EightNum//定义一个EightNum 类{public:int num[9];int f;//初始状态与目标状态相比,棋子错放个数int deap;//深度int evalfun;//状态的估价值EightNum *parent;//以下为类内成员函数的声明EightNum(int nnum[9]);int get_evalfun();int get_deapfun();void eval_func(int id);int Canspread(int n);void Spreadchild(int n);void getnum(int num1[9]);void setnum(int num1[9]);void show(void);int operator ==(EightNum& NewEightN);int operator ==(int num2[9]);int Shownum();};//-----------------------以下为EightNum类成员函数定义-----------------// class Stack{private:EightNum * eightnum;public:Stack * next;EightNum * Minf();EightNum * Belong(EightNum * suc);void Putinto(EightNum * suc);};EightNum::EightNum(int nnum[9]){//此函数功能为:初始化num[];for(int i=0;i<9;i++)num[i]=nnum[i];f=0;deap=0;parent=NULL;}int EightNum::get_evalfun(){return evalfun;}int EightNum::get_deapfun(){return deap;}void EightNum::eval_func(int id){//此函数为估价函数int i,qifa;qifa=0;switch(id){case 1:{for(i=0;i<9;i++){if(num[i]!=target[i])qifa++;}break;}case 2:{int j, h1,h2;for(i=0;i<9;i++){for(j=0;j<9;j++){if(num[j]==i)h1=j;if(target[j]==i)h2=j;}qifa+=(int)(fabs((double)(h1/3 - h2/3)) + fabs((double)(h1%3 - h2%3)));}break;}case 3:{int j, h1,h2;for(i=0;i<9;i++){for(j=0;j<9;j++){if(num[j]==i)h1=j;if(target[j]==i)h2=j;}qifa+=(int)(fabs((double)(h1/3 - h2/3)) + fabs((double)(h1%3 - h2%3)));}qifa=3*qifa;break;}default :break;}f=qifa;if(this->parent==NULL) deap=0;else deap=this->parent->deap+1;evalfun=deap+f;}int EightNum::Canspread(int n){//判断空格"0"可否移动int i,flag = 0;for(i = 0;i < 9;i++)if(this->num[i] == 0)break;switch(n){case 1:if(i/3 != 0)flag = 1;break;case 2:if(i/3 != 2)flag = 1;break;case 3:if(i%3 != 0)flag = 1;break;case 4:if(i%3 != 2)flag = 1;break;default:break;}return flag ;}void EightNum::Spreadchild(int n){//扩展child节点的子节点int i,loc,qifa;for(i = 0;i < 9;i++)this->num[i] = this->parent->num[i];for(i = 0;i < 9;i++)if(this->num[i] == 0)break;if(n==0)loc = i%3+(i/3 - 1)*3;else if(n==1)loc = i%3+(i/3 + 1)*3;else if(n==2)loc = i%3-1+(i/3)*3;elseloc = i%3+1+(i/3)*3;qifa = this->num[loc];this->num[i] = qifa;this->num[loc] = 0;}void EightNum::getnum(int num1[9]){ for(int i=0;i<9;i++)num1[i]=num[i];}void EightNum::setnum(int num1[9]){ for(int i=0;i<9;i++)num[i]=num1[i];}void EightNum::show(){//输出函数for(int i=0;i<9;i++){cout<<num[i]<<" ";if((i+1)%3==0)cout<<"\n";}cout<<"--------------------";}int EightNum::Shownum(){if(this == NULL)return 0;else{int n = this->parent->Shownum();this->show();cout<<endl;return n+1;}}int EightNum::operator ==(EightNum& NewEightN){int compere=1;for(int i=0;i<9;i++)if(num[i]!=NewEightN.num[i]){compere=0;break;}if(compere==0) return 0;else return 1;}//-----------------------以下为分函数的定义---------------------////判断是否有解的函数int solve(int num[9],int target[9]){int i,j;int num_con=0,tar_con=0;for(i=0;i<9;i++)for(j=0;j<i;j++){if(num[j]<num[i] && num[j]!=0)num_con++;if(target[j]<target[i] && target[j]!=0)tar_con++;}num_con=num_con%2;tar_con=tar_con%2;if((num_con==0 && tar_con==0)||(num_con==1 && tar_con==1))return 1;elsereturn 0;}EightNum * Stack::Minf(){Stack * qifa =this->next;Stack * min = this->next;Stack * minp = this;EightNum * minx;while(qifa->next != NULL){if((qifa->next->eightnum->get_evalfun()) < (min->eightnum->get_evalfun())){min = qifa->next;minp = qifa;}qifa = qifa->next;}minx = min->eightnum;qifa = minp->next;minp->next = minp->next->next;free(qifa);return minx;}//判断节点是否属于OPEN表或CLOSED表EightNum * Stack::Belong(EightNum * suc){Stack * qifa = this-> next ;if(qifa == NULL)return NULL;while(qifa != NULL){if(suc==qifa->eightnum)return qifa ->eightnum;qifa = qifa->next;}return NULL;}//把节点存入OPEN 或CLOSED 表中void Stack::Putinto(EightNum * suc){Stack * qifa;qifa =(Stack *) malloc(sizeof(Stack));qifa->eightnum = suc;qifa->next = this->next;this->next = qifa;}int BelongProgram(EightNum * suc ,Stack *Open ,Stack *Closed ,EightNum goal,int m ){EightNum * qifa = NULL;int flag = 0;if((Open->Belong(suc) != NULL) || (Closed->Belong(suc) != NULL)){if(Open->Belong(suc) != NULL) qifa = Open->Belong(suc);else qifa = Closed->Belong(suc);flag=1;}else{Open->Putinto(suc);suc->eval_func(m);}return flag;}//扩展后继节点总函数void Spread(EightNum * suc, Stack * Open, Stack * Closed, EightNum goal,int m){int i;EightNum * child;for(i = 0; i < 4; i++){if(suc->Canspread(i+1)){space++;child = (EightNum *) malloc(sizeof(EightNum));child->parent = suc;child->Spreadchild(i);child->eval_func(m);if(BelongProgram(child, Open, Closed, goal,m)) //判断子节点是否属于OPEN或CLOSED表free(child);}}}//执行函数EightNum * Process(EightNum * org, EightNum goal, Stack * Open, Stack * Closed,int m){while(1){if(Open->next == NULL)return NULL;EightNum * minf =Open->Minf();Closed->Putinto(minf);if((*minf)==goal)return minf;Spread(minf, Open, Closed, goal,m);}}//------------------------A*算法搜索函数----------------------//void A(int id,EightNum start,EightNum Target){EightNum * result;space=0;float time;Stack *Open = (Stack *) malloc(sizeof(Stack));Open->next = NULL;Stack *Closed = (Stack *) malloc(sizeof(Stack));Closed->next = NULL;clock_t startt,finisht;startt=clock();//开始时间start.eval_func(id);Open->Putinto(&start);result = Process(&start, Target, Open, Closed,id); //进行剩余的操作cout<<"\n搜索过程:\n"<<result->Shownum()<<endl;finisht=clock();time=(float)(finisht-startt);cout<<endl<<id<<"算法处理结果:所耗时间:";cout<<time;cout<<"ms, ";cout<<"所耗空间:";cout<<space;cout<<"块, "<<endl<<endl;}//-----------------------------主函数-----------------------------//int main(void)//主函数{int i,j;int flag;int num[9];int error;do{error=0;cout<<"请输入八数码问题的初始状态(0代表空格,“棋子”间用空格隔开):"<<endl;for(i=0;i<9;i++){flag=0;cin>>num[i];for(j=0;j<i;j++)if(num[j]==num[i])flag=1;if(num[i]<0||num[i]>8||flag==1){error++;}}if(error!=0)cout<<"输入数据错误!请重新输入!"<<endl;}while(error!=0);//输入八数码问题的初始状态(0代表空格,“棋子”间用空格隔开);int error1;do{error1=0;cout<<"请输入新的目标状态(用0代表空格,“棋子”间用空格隔开):"<<endl;for(i=0;i<9;i++){flag=0;cin>>target[i];for(j=0;j<i;j++)if(target[j]==target[i])flag=1;if(target[i]<0||target[i]>9||flag==1){error1++;}}if(error1!=0)cout<<"输入数据错误!请重新输入!"<<endl;}while(error1!=0);//输入八数码问题的目标状态(用0代表空格,中间用空格隔开);EightNum start(num),Target(target);int m=solve(num,target);//判断初始状态到目标状态是否有解,有解返回1,误解返回0;if(m==0){cout<<"此状态无解!"<<endl;return 0;}int id=0;while(id!=3){cout<<"1. 错放的棋子个数为;\n2.每个棋子与目标位置之间的距离总和为;"<<endl;cout<<"3.结束,退出程序!"<<endl;cout<<"\n请选择功能,分别输入“1”“2”“3”进行选择:"<<endl;cin>>id;switch(id){case 1:{cout<<"错放的棋子个数结果为:\n(以下逐一展示搜索过程:)"<<endl;A(1,start,Target);break;}case 2:{cout<<"每个棋子与其目标位置之间的距离总和为:\n(以下逐一展示搜索过程:)"<<endl;A(2,start,Target);break;}default: break;}}cout<<"啊啊….程序结束!!";}实验截图实验中遇到的问题1:开始程序只能运行一种方式即按照错位个数搜索,后经过查找相关资料,修改后可程序可进行选择,两种方法结合在一起根据选择运行。
631306050106钟泽伟+状态空间搜索+启发式搜索
重庆交通大学计算机与信息学院验证性实验报告班级:软件开发专业 2013 级一班学号: 631306050106 姓名:钟泽伟实验项目名称:状态空间搜索 8数码问题实验项目性质:验证性实验实验所属课程:人工智能实验室(中心):软件中心实验室(语音楼8楼)指导教师:朱振国实验完成时间:年月日1. 熟悉人工智能系统中的问题求解过程;2. 熟悉状态空间的盲目搜索和启发式搜索算法的应用;3. 熟悉对八数码问题的建模、求解及编程语言的应用。
二、实验内容及要求在一个3*3的九宫中有1-8个数码及一个空格随即的摆放在其中的格子里,现在要求实验这个问题:将该九宫格调整为某种有序的形式。
调整的规则是,每次只能将与空格(上、下、左、右)相邻的一个数字平移到空格中。
三、实验设备及软件VC++四、设计方案㈠题目状态空间搜索8数码问题㈡设计的主要思路a、把初始数码组压入队列;b、从队列中取出一个数码组节点;c、扩展子节点,即从上下左右四个方向移动空格,生成相应子节点:d、对子节点数码组作评估,是否为优越节点,即其评估值是否小于等于其父节点加一,是则将其压入队,否则抛弃。
e、判断压入队的子节点数码组(优越点)的评估值,为零则表示搜索完成,退出搜索;f、跳到步骤2㈢主要功能在通向目标节点的路径上,各节点的数码格局同目标节点相比较,其数码不同的位置个数在逐渐减少,最后为零,因此可以把数码不同的位置个数作为标志一个节点到目标节点距离远近的一个启发性信息,利用这个信息来扩展节点的选择,减少搜索范围,提高搜索速度。
五、主要代码include <stdio.h> } //设计了搜索深度范围,防止队列内存越界#include <stdlib.h> 6、运行结果#include <time.h>#define N 3 //数码组大小#define Max_Step 50 //最大搜索深度#define MAX 50typedef struct node//八数码结构体{int form[N][N];//数码组int evalue;//评估值int udirect;//所屏蔽方向,防止往回推到上已状态,1上2下3左4右struct node *parent;//父节点/////////打印数码组void Print(Graph *The_graph){int i,j;if(The_graph==NULL)printf("图为空\n");else{printf("---------------------\n");for(i=0;i<N;i++){printf("|\t");for(j=0;j<N;j++){printf("%d\t",The_graph->form[i][j]);//遍历打印}printf("\t|\n");}printf("|\t\t\t差距:%d\t|\n",The_graph->evalue);//差距显示printf("---------------------\n");}}/////////评价函数int Evaluate(Graph *The_graph,Graph *End_graph){int valute=0;//差距数int i,j;for(i=0;i<N;i++){for(j=0;j<N;j++){if(The_graph->form[i][j]!=End_graph->form[i][j]){valute++;}}}The_graph->evalue=valute;return valute;}/////////移动数码组Graph *Move(Graph *The_graph,int Direct,int CreatNew_graph) {Graph *New_graph;//int HasGetBlank=0;//是否获取空格位置int AbleMove=1;//是否可移动int i,j,t_i,t_j,x,y;for(i=0;i<N;i++)//获取空格坐标i,j {for(j=0;j<N;j++){if(The_graph->form[i][j]==0){HasGetBlank=1;break;}}if(HasGetBlank==1)break;}//printf("空格位置:%d,%d\n",i,j);t_i=i;t_j=j;//移动空格switch(Direct){case 1://上t_i--;if(t_i<0)AbleMove=0;break;case 2://下t_i++;if(t_i>=N)AbleMove=0;break;case 3://左t_j--;if(t_j<0)AbleMove=0;break;case 4://右t_j++;if(t_j>=N)AbleMove=0;break;}if(AbleMove==0)//不能移动则返回原节点{return The_graph;}if(CreatNew_graph==1){New_graph=(Graph *)malloc(sizeof(Graph));//生成节点for(x=0;x<N;x++){for(y=0;y<N;y++){New_graph->form[x][y]=The_graph->form[x][y];//复制数码组}}}else{New_graph=The_graph;}//移动后New_graph->form[i][j]=New_graph->form[t_i][t_j];New_graph->form[t_i][t_j]=0;//printf("移动产生的新图:\n");//Print(New_graph);return New_graph;}/////////搜索函数Graph *Search(Graph *Begin,Graph *End){Graph *g1,*g2,*g;int Step=0;//深度int Direct=0;//方向int i;int front,rear;front=rear=-1;//队列初始化g=NULL;rear++;//入队Qu[rear]=Begin;while(rear!=front)//队列不空{front++;//出队g1=Qu[front];//printf("开始第%d个图:\n",front);//Print(g1);for(i=1;i<=4;i++)//分别从四个方向推导出新子节点{Direct=i;if(Direct==g1->udirect)//跳过屏蔽方向continue;g2=Move(g1, Direct, 1);//移动数码组if(g2!=g1)//数码组是否可以移动{//可以移动Evaluate(g2, End);//评价新的节点//printf("开始产生的第%d个图:\n",i);//Print(g2);if(g2->evalue<=g1->evalue+1){//是优越节点g2->parent=g1;//移动空格switch(Direct)//设置屏蔽方向,防止往回推{case 1://上g2->udirect=2;break;case 2://下g2->udirect=1;break;case 3://左g2->udirect=4;break;case 4://右g2->udirect=3;break;}rear++;Qu[rear]=g2;//存储节点到待处理队列if(g2->evalue==0)//为0则搜索完成{g=g2;//i=5;break;}}else{free(g2);//抛弃劣质节点g2=NULL;}}}if(g!=NULL)//为0则搜索完成{if(g->evalue==0){break;}}Step++;//统计深度if(Step>Max_Step){break;}}return g;}/////////初始化一个八数码结构体Graph *CR_BeginGraph(Graph *The_graph) {srand((unsigned)time(0));int M=10;//随机移动步数int Direct;int i,x,y;Graph *New_graph;New_graph=(Graph *)malloc(sizeof(Graph));for(x=0;x<N;x++){for(y=0;y<N;y++){New_graph->form[x][y]=The_graph->form[x][y];}}for(i=0;i<M;i++){Direct=rand()%4+1;//产生1-4随机数//printf("Direct:%d\n",Direct);New_graph=Move(New_graph, Direct, 0);//Print(New_graph);}New_graph->evalue=0;New_graph->udirect=0;New_graph->parent=NULL;return New_graph;}int main (int argc, const char * argv[]){// insert code here.../*Graph Begin_graph={{{2,8,3},{1,6,4},{0,7,5}},0,0,NULL};Graph Begin_graph={{{2,8,3},{1,0,4},{7,6,5}},0,0,NULL};Graph Begin_graph={{{2,0,1},{4,6,5},{3,7,8}},0,0,NULL};*///目标数码组Graph End_graph={{{1,2,3},{8,0,4},{7,6,5}},0,0,NULL};//初始数码组Graph *Begin_graph;Begin_graph=CR_BeginGraph(&End_graph);//随机产生初始数码组Evaluate(Begin_graph, &End_graph);//对初始的数码组评价printf("初始数码组:\n");Print(Begin_graph);printf("目标数码组:\n");Print(&End_graph);Graph *G,*P;int top=-1;//图搜索G=Search(Begin_graph, &End_graph);//打印if(G){//把路径倒序P=G;//压栈while(P!=NULL){top++;St[top]=P;P=P->parent;}printf("<<<<<<<<<<<<<<<搜索结果>>>>>>>>>>>>>>>>\n");//弹栈打印while(top>-1){P=St[top];top--;Print(P);}printf("<<<<<<<<<<<<<<<<<完成>>>>>>>>>>>>>>>>>>\n");}else{printf("搜索不到结果,深度为%d\n",Max_Step);//设计搜索深度范围主要是防止队列内存越界}return 0;六、测试结果及说明七、实验体会通过这次实验我体会到了人工智能的思想,深知人工智能对软件行业未来的前景,并且通过这次实验我的编程能力和算法能力又得到了锻炼,虽然过程磕磕巴巴,但结果很美好。
重排九宫实验报告
重排九宫实验报告重排九宫算法实验报告1实验⽬的运⽤搜索算法重排九宫使之从初始状态到底⽬标状态,并求解最短路径。
2 实验内容⽤三种不同的搜索算法实现重排九宫。
本实验⽤的⽅法分别是:A*算法、有界深度优先搜索和⼴度优先搜索。
3 实验原理启发式搜索是在搜索中加⼊了与问题有关的启发性信息,⽤以指导搜索朝着最有希望的⽅向前进,加速问题的求解过程并找到最优解。
A*算法是⼀种启发式搜索。
⼴度优先搜索按照“先扩展出的节点先被考察”的原则进⾏搜索。
深度优先搜索按照“后扩展出的节点先被考察”的原则进⾏搜索。
有界深度优先搜索的原则与深度优先搜索相同,但是它规定了深度限界,使搜索不得⽆限制地向纵深⽅向发展。
4解存在算法如下图所⽰:判断是否有解的算法如下:public class Method {public static boolean Parity(int a[]){boolean parity=true;for(int i=0;iint k=i;for(int j=i+1;jif(a[k]>a[j]){k=j;}}if(k!=i){int temp;temp=a[i];}}return parity;}public static boolean isSolutionExist(int src[],int dest[],int s[][],int d[][]){ int row1=0,row2=0,clumn1=0,clumn2=0; boolean flag1,flag2;for(int i=0;i<3;i++){for(int j=0;j<3;j++){if(s[i][j]==0){row1=i;clumn1=j;}if(d[i][j]==0){row2=i;clumn2=j;}}}if((row1-row2+clumn1-clumn2)%2==0){flag1=true;}else{flag1=false;}if(Parity(src)==Parity(dest)){flag2=true;}else{flag2=false;}if(flag1==flag2){return true;}else{return false;}节点数据结构private static class Node{int data[][]; //状态int row; //0所在⾏int clumn; //0所在列Node parent; //⽗亲节点Node(int data[][],Node parent,int row,int clumn){ this.data=data;this.parent=parent;this.row=row;this.clumn=clumn;}}运⾏截图1.初始化状态2.初始状态随机3.初始和⽬标状态都为随机6有界深度优先搜索节点数据结构private static class Node{boolean flag=false;int depth=-1;int data[][];int row;int clumn;Node parent;Node(int data[][],Node parent,int row,int clumn,int depth){ this.data=data; this.parent=parent;this.row=row;this.clumn=clumn;this.depth=depth;}运⾏截图1.7 A*算法节点数据结构private static class Node{int value; //估价函数的值int diff=0; //当前节点到⽬标节点的最⼩代价int depth=-1; //初始节点到当前节点的代价int data[][];int row;int clumn;Node parent;Node(int data[][],Node parent,int row,int clumn,int depth,int diff){ this.data=data; this.parent=parent;this.row=row;this.clumn=clumn;this.depth=depth;this.diff=diff;this.value=depth+diff;}}7 A*算法运⾏截图。
rgzn
《人工智能》实验报告专业计算机科学与技术年级大三姓名吕小春学号 0927401108指导老师实验室使用日期苏州大学计算机科学与技术学院统一印制二零零二年八月实验一启发式搜索一、实验目的:熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A算法求解九宫问题,理解求解流程和搜索顺序。
二、实验方法:1.先熟悉启发式搜索算法;2.用C、C++或JA V A 语言编程实现实验内容。
三、实验内容:问题描述:用启发式搜索方法求解下列九宫问题四、实验步骤(1)状态表示的数据结构static int target[9]={1,2,3,8,0,4,7,6,5}; 全局静态变量,表示目标状态class eight_num{private:int num[9]; 定义八数码的初始状态int not_in_position_num; 定义不在正确位置八数码的个数int deapth; 定义了搜索的深度int eva_function; 评价函数的值,每次选取最小的进行扩展public:eight_num* parent; 指向节点的父节点eight_num* leaf_next; 指向open表的下一个节点eight_num* leaf_pre; 指向open 表的前一个节点初始状态的构造函数eight_num(int init_num[9]);eight_num(int num1,int num2,int num3,int num4,int num5,int num6,int num7,int num8,int num9){} eight_num(void){ }计算启发函数g(n)的值void eight_num::cul_para(void){}显示当前节点的状态void eight_num::show(){}复制当前节点状态到一个另数组中void eight_num::get_numbers_to(int other_num[9]){}设置当前节点状态(欲设置的状态记录的other数组中)void eight_num::set_num(int other_num[9]){}eight_num& eight_num::operator=(eight_num& another_8num){}eight_num& eight_num::operator=(int other_num[9]){}int eight_num::operator==(eight_num& another_8num){}int eight_num::operator==(int other_num[9]){}空格向上移int move_up(int num[9]){}空格向下移int move_down(int num[9]){}空格向左移int move_left(int num[9]){}空格向右移int move_right(int num[9]){}判断可否解出int icansolve(int num[9],int target[9]){}判断有无重复int existed(int num[9],eight_num *where){}寻找估价函数最小的叶子节点eight_num* find_OK_leaf(eight_num* start){}}(2)状态扩展规则的表示算法的功能:产生8数码问题的解(由初始状态到达目标状态的过程)输入:初始状态,目标状态输出:从初始状态到目标状态的一系列过程算法描述:Begin:读入初始状态和目标状态,并计算初始状态评价函数值f;根据初始状态和目标状态,判断问题是否可解;If(问题可解)把初始状态假如open表中;While(未找到解&&状态表非空)①在open表中找到评价值最小的节点,作为当前结点;②判断当前结点状态和目标状态是否一致,若一致,跳出循环;否则跳转到③;③对当前结点,分别按照上、下、左、右方向移动空格位置来扩展新的状态结点,并计算新扩展结点的评价值f并记录其父节点;④对于新扩展的状态结点,判断其是否重复,若不重复,把其加入到open表中;⑤把当前结点从open表中移除;End whileEnd if输出结果;End(3)搜索产生的状态空间图(4)OPEN表和CLOSE表变化过程1)把起始节点S放入OPEN表,计算估价函数f (s)2)如果OPEN表判断为空,则失败无解,否则则程序继续3)将OPEN表中估价函数f(s)最小的节点取出并放入CLOSE表中4)判断该节点是否为目标节点,是则搜索成功,结束程序,否则继续5)用拓展函数拓展该节点,得到其后继结点并算每一个后继结点的估价函数值,在算一下是否有后继结点与OPEN表和CLOSE表中的重复,再将后继结点放入OPEN表中并进行重新排序。
人工智能-启发式搜索
实验报告姓名:***学号:**********班级:软件二班实验名称:启发式搜索课程名称:人工智能实验日期:2015.11.09实验环境:Visual C++实验目的以及内容:1、实验内容:使用启发式搜索算法求解八数码问题。
(1)编制程序实现求解八数码问题A*算法,采用估价函数其中:d(n)是搜索树中节点n的深度;w(n)为节点n的数据库中错放的棋子个数;p(n)为节点n的数据库中的每个棋子与其目标位置之间的距离的总和。
(2)分析上述(1)中的两种估价函数求解八数码问题的效率差别,给出一个是p(n)的上界的h(n)的定义,并测试使用该估价函数是否使算法失去可采纳性。
2、实验目的:熟练的掌握启发式搜索A*算法及其可采纳性。
3. 实验原理:八数码问题是在3行和3列构成的九宫棋盘上放置数码为1到8的8个棋盘,剩下一个空格的移动来不断改变棋盘的布局,求解这类问题的方法是:给定初始布局(即初始状态)和目标布局(即目标状态),定义操作算子的直观方法是为每个棋牌制定一套可能的走步》上,下,左,右四种移动,再根据所定义的启发式搜索函数在搜索过程中选择最合适的操作算子,得到最优的路径。
代码:#include"stdio.h"#define num 3void show(int begin[num][num]){for(int i = 0; i < num; i++){for(int j = 0; j < num; j++)printf("%d ", begin[i][j]);printf("\n");}printf("\n");}void exchange(int begin[num][num], int row_one, int column_one, int row_two, int column_two){int temp;temp = begin[row_two][column_two] ;begin[row_two][column_two] = begin[row_one][column_one];begin[row_one][column_one] = temp;}int judge(int begin[num][num], int end[num][num]){int count=0;for(int i = 0; i < num; i++)for(int j = 0; j < num; j++){if(begin[i][j] == end[i][j] && end[i][j] != 0)count++;}return count;}int yidong(int begin[num][num], int end[num][num], int right, int jishu, int ji_shu[50][3][3], int biaoji, int row, int column){int temp_zhi;show(begin);if(jishu >= 20)return 0;int node;int temp;for(int q=0; q<jishu; q++){node = 1;for(int w=0; w<num && node; w++)for(int r=0; r<num && node; r++)if(ji_shu[q][w][r] != begin[w][r])node = 0;if(node == 1){return 0;}}for(int i = 0; i < num; i++)for(int j = 0; j < num; j++)ji_shu[jishu][i][j] = begin[i][j];if(right == num * num - 1)return 1;if(row > 0 && biaoji != 0){exchange(begin, row - 1, column, row , column);temp = judge(begin, end);if(temp < right)exchange(begin, row - 1, column, row , column);else if(temp >= right){temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu, 2, row-1, column);if( temp_zhi == 1)return 1;exchange(begin, row - 1, column, row , column);}}if(column > 0 && biaoji != 1){exchange(begin, row, column - 1, row , column);temp = judge(begin, end);if(temp < right)exchange(begin, row, column - 1, row , column);else if(temp >= right){temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu ,3, row, column -1);if(temp_zhi == 1)return 1;exchange(begin, row, column - 1, row , column);}}if(row < num-1 && biaoji != 2){exchange(begin, row + 1, column, row , column);temp = judge(begin, end);if(temp < right)exchange(begin, row + 1, column, row , column);else if(temp >= right){temp_zhi =yidong(begin, end, temp, jishu+1, ji_shu, 0, row+1, column);if(temp_zhi == 1)return 1;exchange(begin, row + 1, column, row , column);}}if(column < num-1 && biaoji != 3){exchange(begin, row, column + 1, row , column);temp = judge(begin, end);if(temp < right)exchange(begin, row, column + 1, row , column);else if(temp >= right){temp_zhi = yidong(begin, end, temp, jishu+1, ji_shu, 1, row, column+1);if(temp_zhi == 1)return 1;exchange(begin, row, column + 1, row , column);}}return 0;}void shuru(int begin[][num],int blank[]){int temp, node, zero = 0;for (int i = 0; i < num; i++)for(int j = 0; j < num; j++){node = 1;printf("请输入第%d行,第%d列的元素的值:", i+1, j+1);scanf("%d", &temp);for (int q = 0; q <= i && node == 1; q++)for (int w = 0; w < j; w++)if(temp == begin[q][w]){printf("输入重复,请重新输入\n");node = 0;j--;break;}if(temp < 0 || temp > num*num-1){printf("请输入从%d到%d的数\n", zero, num*num-1);node = 0;j--;}if(node == 1){if(temp == 0){blank[0] = i;blank[1] = j;}begin[i][j] = temp;}}}int main(){int jishu = 0, ji_shu[50][3][3];int row;int column;int begin[num][num], blank[2],count=1;int end[num][num] = {1, 2, 3, 8, 0, 4, 7, 6, 5};printf ("-------8数码游戏开始!--------\n");shuru(begin, blank);row = blank[0];column = blank[1];if(yidong (begin, end,judge(begin,end),jishu,ji_shu,4,row,column) == 0)printf("\n此8数码的问题可能无解!");elseshow(begin);getchar();getchar();return 0;}实验截图:实验总结:1、A*搜索算法:取g(n)=d(n),h(n)=w(n),其中w(n)表示以目标为基准,结点n的状态中每一个数码牌与其目标位置之间的距离(不考虑夹在其间的数码牌)的总和,由于从结点n转换成目标结点至少需要w(n)步,所以对任意n,恒有w(n) ≤h*(n)。
启发式搜索算法范文
启发式搜索算法范文
启发式算法
一、概述
启发式算法是一种智能算法,它使用了一定的启发式信息来根据当前状态,推测要找到最优解的最有可能的选择,以找到问题的最优解。
这类算法不是把所有可能的情况都考虑进去,而是根据当前信息和历史信息推测出最有可能的解,从而缩小空间,加快速度。
二、启发式的原理
启发式算法的核心思想是:以其中一种形式编码给定问题,然后以其中一种方式状态空间,得到最优解。
状态空间表示可以到达的所有状态,通常用一棵树表示。
启发式算法利用一定的经验和知识来指导,并尽可能快速地得到所需要的答案。
常用算法有回溯法、遗传算法、模拟退火算法、启发式A*算法等。
其中,回溯法是一种暴力算法,主要用在状态空间树上;遗传算法是一种模拟生物进化学习的算法;模拟退火算法是一种模拟物理热力学的算法;启发式A*算法是一种基于启发式函数(Heuristicc Function)的算法。
三、启发式的应用
启发式算法具有许多应用,如地图路径查找、空间优化、赛车、基因算法、寻路、网络传输调度等。
启发式搜索实验报告
启发式搜索实验报告2015-2016第1学期《人工智能基础》实验报告实验名称:启发式搜索算法专业班级学号姓名1、实验环境Visual C++ 6.02、实验目的和要求(复述问题)使用启发式算法求解8数码问题(1) 编制程序实现求解8数码问题A*算法,采用估价函数f(n)=d(n)+p(n)其中:d(n)是搜索树中结点n的深度;w(n)为节点n的数据库中错放的旗子个数;p(n)为结点n的数据库中每个棋子与其目标位置之间的距离总和。
(2) 分析上述(1)中两种估价函数求解8数码问题的效率差别,给出一个是p(n)的上界h(n)的定义,并测试该估价函数是否使算法失去可采纳性。
实验目的:熟练掌握启发式搜索A*算法及其可采纳性。
3、解题思路、代码3.1解题思路八数码问题的求解算法(1) 盲目搜索宽度优先搜索算法、深度优先搜索算法(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)1 / 112015-2016第1学期《人工智能基础》实验报告其中A*算法中的g(n)根据具体情况设计为d(n),意为n节点的深度,而h(n)设计为p(n),意为放错的数码与正确的位置距离之和。
人工智能实验报告
****大学人工智能基础课程实验报告(2011-2012学年第一学期)启发式搜索王浩算法班级: *********** 学号: ********** 姓名: ****** 指导教师: ******成绩:2012年 1 月 10 日实验一 启发式搜索算法1. 实验内容:使用启发式搜索算法求解8数码问题。
⑴ 编制程序实现求解8数码问题A *算法,采用估价函数()()()()w n f n d n p n ⎧⎪=+⎨⎪⎩, 其中:()d n 是搜索树中结点n 的深度;()w n 为结点n 的数据库中错放的棋子个数;()p n 为结点n 的数据库中每个棋子与其目标位置之间的距离总和。
⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是()p n 的上界的()h n 的定义,并测试使用该估价函数是否使算法失去可采纳性。
2. 实验目的熟练掌握启发式搜索A *算法及其可采纳性。
3. 实验原理使用启发式信息知道搜索过程,可以在较大的程度上提高搜索算法的时间效率和空间效率;启发式搜索的效率在于启发式函数的优劣,在启发式函数构造不好的情况下,甚至在存在解的情形下也可能导致解丢失的现象或者找不到最优解,所以构造一个优秀的启发式函数是前提条件。
4.实验内容1.问题描述在一个3*3的九宫格 里有1至8 八个数以及一个空格随机摆放在格子中,如下图:初始状态 目标状态现需将图一转化为图二的目标状态,调整的规则为:每次只能将空格与其相邻的一个数字进行交换。
实质是要求给出一个合法的移动步骤,实现从初始状态到目标状态的转变。
2.算法分析(1)解存在性的讨论对于任意的一个初始状态,是否有解可通过线性代数的有关理论证明。
按数组存储后,算出初始状态的逆序数和目标状态的逆序数,若两者的奇偶性一致,则表明有解。
(2)估价函数的确定通过对八数码的特性的研究,找出一个相对好的函数,f(n)=d(n)+h(n)其中h(n)=2*compare(n)+3*S(n);d(n)为已搜索的深度;(compare(n)为当前节点与目标结点相同位置不相同的个数,S(n)为当前节点的无序度。
人工智能实验报告-八数码(五篇模版)
人工智能实验报告-八数码(五篇模版)第一篇:人工智能实验报告-八数码《人工智能》实验一题目实验一启发式搜索算法1.实验内容:使用启发式搜索算法求解8数码问题。
⑴ 编制程序实现求解8数码问题A*算法,采用估价函数⎧⎪w(n),f(n)=d(n)+⎨pn⎪⎩()其中:d(n)是搜索树中结点n的深度;w(n)为结点n的数据库中错放的棋子个数;p(n)为结点n的数据库中每个棋子与其目标位置之间的距离总和。
⑵ 分析上述⑴中两种估价函数求解8数码问题的效率差别,给出一个是p(n)的上界的h(n)的定义,并测试使用该估价函数是否使算法失去可采纳性。
2.实验目的熟练掌握启发式搜索A算法及其可采纳性。
3.数据结构与算法设计该搜索为一个搜索树。
为了简化问题,搜索树节点设计如下:typedef struct Node//棋盘 {//节点结构体int data[9];double f,g;struct Node * parent;//父节点}Node,*Lnode;int data[9];数码数组:记录棋局数码摆放状态。
struct Chess * Parent;父节点:指向父亲节点。
下一步可以通过启发搜索算法构造搜索树。
1、局部搜索树样例:*2、搜索过程搜索采用广度搜索方式,利用待处理队列辅助,逐层搜索(跳过劣质节点)。
搜索过程如下:(1)、把原棋盘压入队列;(2)、从棋盘取出一个节点;(3)、判断棋盘估价值,为零则表示搜索完成,退出搜索;(4)、扩展子节点,即从上下左右四个方向移动棋盘,生成相应子棋盘;(5)、对子节点作评估,是否为优越节点(子节点估价值小于或等于父节点则为优越节点),是则把子棋盘压入队列,否则抛弃;(5)、跳到步骤(2);3、算法的评价完全能解决简单的八数码问题,但对于复杂的八数码问题还是无能为力。
现存在的一些优缺点。
1、可以改变数码规模(N),来扩展成N*N的棋盘,即扩展为N 数码问题的求解过程。
嗨呀搜索实验报告
一、实验目的1. 理解搜索算法的基本概念和原理;2. 掌握A搜索算法的原理和实现方法;3. 分析A搜索算法的优缺点;4. 通过实验验证A搜索算法在实际问题中的应用效果。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3. 库:numpy、matplotlib三、实验内容1. A搜索算法原理介绍2. A搜索算法实现3. 实验数据准备4. 实验结果分析5. 结论与反思四、实验原理A搜索算法是一种启发式搜索算法,它利用启发函数来评估节点的重要性,并根据评估结果进行搜索。
A搜索算法的评估函数为:f(n) = g(n) + h(n)其中,g(n)表示从起始节点到当前节点n的实际代价,h(n)表示从当前节点n到目标节点的估计代价。
五、实验步骤1. A搜索算法原理介绍A搜索算法是一种结合了最佳优先搜索和贪婪搜索的搜索算法。
它通过评估函数f(n)来评估每个节点的优先级,优先选择f(n)最小的节点进行扩展。
其中,g(n)表示从起始节点到当前节点n的实际代价,h(n)表示从当前节点n到目标节点的估计代价。
2. A搜索算法实现使用Python实现A搜索算法,包括以下步骤:(1)定义节点类:包含节点的位置、父节点、g(n)、h(n)和f(n)等属性;(2)定义启发函数:计算节点到目标节点的估计代价h(n);(3)定义搜索函数:实现A搜索算法的搜索过程。
3. 实验数据准备设计一个简单的迷宫地图,其中1表示障碍,0表示通路。
迷宫的起始节点为左上角,目标节点为右下角。
4. 实验结果分析运行A搜索算法,记录搜索过程和搜索结果。
通过可视化工具(如matplotlib)展示搜索过程,分析A搜索算法的搜索路径和搜索效率。
5. 结论与反思(1)A搜索算法在实际问题中具有较好的搜索性能,能够快速找到最优路径;(2)A搜索算法的启发函数对搜索性能有很大影响,需要根据实际问题选择合适的启发函数;(3)A搜索算法在处理大型数据集时,计算量较大,可能需要优化算法或使用其他搜索算法。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验名称:启发式搜索算法1、实验环境Visual C++ 6.02、实验目的和要求(复述问题)使用启发式算法求解8数码问题(1)编制程序实现求解8数码问题A*算法,采用估价函数f(n)=d(n)+p(n)其中:d(n)是搜索树中结点n的深度;w(n)为节点n的数据库中错放的旗子个数;p(n)为结点n的数据库中每个棋子与其目标位置之间的距离总和。
(2)分析上述(1)中两种估价函数求解8数码问题的效率差别,给出一个是p(n)的上界h(n)的定义,并测试该估价函数是否使算法失去可采纳性。
实验目的:熟练掌握启发式搜索A*算法及其可采纳性。
3、解题思路、代码3.1解题思路八数码问题的求解算法(1)盲目搜索宽度优先搜索算法、深度优先搜索算法(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)设计为p(n),意为放错的数码与正确的位置距离之和。
由于实际情况中,一个将牌的移动都是单步进行的,没有交换拍等这样的操作。
所以要把所有的不在位的将牌,移动到各自的目标位置上,至少要移动从他们各自的位置到目标位置的距离和这么多次,所以最有路径的耗散值不会比该值小,因此该启发函数h(n)满足A*算法的条件。
3.2代码#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]={1,2,3,8,0,4,7,6,5};//------------------------------------------------------------------------//添加节点函数入口,方法:通过插入排序向指定表添加//------------------------------------------------------------------------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值,后者小则什么也不做。