八数码难题

合集下载

八数码问题解释

八数码问题解释

八数码问题解释8数码问题又称9宫问题,源于一个古老的智力游戏。

说白了就是我们小时候玩的“华容道”。

意在给定的9格棋盘的8个格子内分别放一个符号,符号之间互不相同,剩下一格做为“出口”。

我们把8个符号在棋盘上的排列顺序称作8数码的状态,游戏要求给定一个初始的状态与一个终止状态,符号要经过若干次移动后由初态变成终态,这个过程中只有“出口”附近的符号可以朝“出口”的方向移动,且每次只能移动一个符号。

如下图所示,(其中我们用0表示出口,=》表示移动一次,=》*表示移动0-n次):初态终态1 2 3 1 2 3 0 1 24 5 6 =》 4 5 6 =》* 3 4 57 8 0 7 0 8 6 7 82 解决方案通过观察我们可以发现每一次8数码的状态都可以通过移动字符变成有限的几种其他状态,比如上图中我们可以知道初态“出口”附近有8和6可以移动,那么这个初态可以经过移动得到两个新的状态。

我们人在玩这个游戏的时候,总是要做下面几个步骤:1.看看哪个符号可以移动。

2.判断一下哪个符号的移动最有利于到达终态。

3.选定一个符号并移动它。

4.判断是否到达终态,是则结束,否则就回到第一步。

而现在我们要使用机器来模拟这一过程,其步骤与人类类似,但不同的是,人在执行第二部的时候总是能预先判断未来好几步的局势,从而选出最有利的一步,而机器则不行,它要先得到一个状态才能知道这个状态下一步将会到哪些状态而无法像我们一样一次就看到后面几步的状态。

那么基本思想就是让机器穷尽由初态出发到达所有可能状态的路径,并从中找到有终态的路径作为问题的解。

2.1 A*算法就如我们上面说到的让机器找出所有的可能来得到问题的解,看起来似乎很简单,但问题在于一旦8数问题的解达到一定规模,机器所要穷尽的路径数量将变得极为庞大,无疑会消耗大量的时间和空间。

那么如何让机器像人一样在选择移动符号的时候总是能选择最有利的那一个呢?下面就要介绍启发式搜索中的一个算法A*算法来解决这个问题。

人工智能8位数码难题的问题求解

人工智能8位数码难题的问题求解
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3
#define Bit char
typedef struct maps
{
Bit detail[9];
int myindex; //记录自己节点在hash表中的位置
Bit position; //记录空格(0)在序列中的位置
实验软硬件要求:网络计算机,c++编程环境
实验内容、方法和步骤(可附页)
我们将八数码难题分布在3×3方格棋盘上,分别放置了标有数字1,2,3,4,5,6,7,8的八张牌,初始状态S0,目标状态如图所示,可以使用的操作有:空格上移,空格左移,空格右移,空格下移。我们将是用广度优先搜索算法来解决这一问题。
int newindex = Parent.myindex ;
Bit *p = Parent.detail;
switch(direct)
{
case UP :
{
newindex -= 3*40320 ;
newindex += ( p[ i - 2 ] > p[ i - 3 ]) ? ( Factorial[ p[ i - 3 ] ] ) : ( - Factorial[ p[ i - 2 ] ] );
}p,*PMap;
Map org; //初始状态
int EndIndex; //目标,上移,下移,左移,右移
int const derection[4] ={ -3 , 3 , -1 , 1 } ;
//可移动的四个方向
int const Factorial[9] = {40320 , 5040 , 720 , 120 , 24 , 6 , 2 , 1 , 1 };

八数码问题 实验报告

八数码问题 实验报告

八数码问题实验报告八数码问题实验报告引言:八数码问题是一种经典的数学难题,在计算机科学领域有着广泛的研究和应用。

本实验旨在通过探索八数码问题的解法,深入理解该问题的本质,并通过实验结果评估不同算法的效率和准确性。

一、问题描述:八数码问题是一个在3×3的棋盘上,由1至8的数字和一个空格组成的拼图问题。

目标是通过移动棋盘上的数字,使得棋盘上的数字排列按照从小到大的顺序排列,最终形成如下的目标状态:1 2 34 5 67 8二、解法探索:1. 深度优先搜索算法:深度优先搜索算法是一种经典的解决拼图问题的方法。

该算法通过不断尝试所有可能的移动方式,直到找到目标状态或者无法再继续移动为止。

实验结果显示,该算法在八数码问题中能够找到解,但由于搜索空间庞大,算法的时间复杂度较高。

2. 广度优先搜索算法:广度优先搜索算法是另一种常用的解决八数码问题的方法。

该算法通过逐层扩展搜索树,从初始状态开始,逐步扩展所有可能的状态,直到找到目标状态。

实验结果显示,该算法能够找到最短路径的解,但同样面临搜索空间庞大的问题。

3. A*算法:A*算法是一种启发式搜索算法,结合了深度优先搜索和广度优先搜索的优点。

该算法通过使用一个估价函数来评估每个搜索状态的优劣,并选择最有希望的状态进行扩展。

实验结果显示,A*算法在八数码问题中表现出色,能够高效地找到最优解。

三、实验结果与分析:通过对深度优先搜索、广度优先搜索和A*算法的实验,得出以下结论:1. 深度优先搜索算法虽然能够找到解,但由于搜索空间庞大,时间复杂度较高,不适用于大规模的八数码问题。

2. 广度优先搜索算法能够找到最短路径的解,但同样面临搜索空间庞大的问题,对于大规模问题效率较低。

3. A*算法在八数码问题中表现出色,通过合理的估价函数能够高效地找到最优解,对于大规模问题具有较好的效果。

四、结论与展望:本实验通过对八数码问题的解法探索,深入理解了该问题的本质,并评估了不同算法的效率和准确性。

用A算法解决八数码问题

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

八数码问题

八数码问题

八数码问题
八数码问题是一个经典的问题,也称为滑动谜题。

问题的描述是:在一个3x3的棋盘上,有1-8这8个数字和一个空格组成的九个格子,目标是通过移动数字,将棋盘上的数字按从小到大的顺序排列,空格在最后一个位置。

解决这个问题的算法主要有搜索算法,其中最常见的是A*算法。

A*算法是一种启发式搜索算法,通过建立一个状态空间图,并使用启发式函数估算每个状态到目标状态的距离,来优化搜索过程。

在八数码问题中,启发式函数可以使用曼哈顿距离来估算。

另外,也可以使用深度优先搜索、广度优先搜索、IDA*等搜索算法来解决八数码问题。

这些算法在搜索过程中以不同的方式遍历状态空间图,找到最优解。

解决八数码问题的具体步骤一般如下:
1. 定义初始状态和目标状态。

2. 使用搜索算法进行搜索,找到从初始状态到目标状态的最优解。

3. 在搜索过程中,需要注意状态的合法性和重复状态的处理。

4. 输出最优解,即一系列移动操作,将初始状态转化为目标状态。

需要注意的是,八数码问题可能存在无解的情况,需要在搜索过程中判断并处理无解情况。

此外,由于八数码问题的状态空间较大,搜索过程可能需要一定的时间和空间复杂度。

因此,在实现解决算法时,需要考虑性能优化的问题。

多种方法解决八数码难题.ppt

多种方法解决八数码难题.ppt

I(5) 23 5
J(7) 23
184
184
765
765
K(5) 123
6
84
765 M(7)
05 启发式搜索 Heuristic Search
问题重述
Problem Retelling
八数码问题描述
3×3九宫棋盘,放置数码为1 -8的8个棋牌,剩下一个空格,只能通过棋牌向空格的移动 来改变棋盘的布局。 要求:根据给定初始布局(即初始状态)和目标布局(即目标状态),如何移动棋牌才能从 初始布局到达目标布局,找到合法的走步序列。
深度优先搜索算法解决八数码难题
123
8
4
765 (目标状态)
4 283 164
75
283 64
…1 7 5
3 283 164 75
283 164 75

2
283 14 765
283 14
…7 6 5
283 14
…7 6 5
1 23 184 765
23 184 765
23 184 765
123 84
黑色数字表示不 在位的将牌数
A(6) 283 164
75
S(4) 初始 2 8 3 1
164 75
B(4) 283
2
14
765
C(6) 283 164 75
G(6) 83
214 765
D(5) 283 3
14 765
H(7) 283 714
65
L(5)
1 8
2
3 4
7
765
E(5) 2 34
184
765
开始
有序搜索算法框图

人工智能 八数码难题

人工智能 八数码难题

实验报告课程名称人工智能_____________实验项目八数码难题______________实验仪器电脑、visual C++_________系别____________ 专业__ _____班级/学号学生姓名_ _________实验日期____成绩_______________________指导教师_________一、实验目的理解并熟悉掌握深度优先搜索和广度优先搜索地方法。

二、实验内容九宫格中有8个数码,其中只有一个空,规则是只能把一个数码移动到空的格子中,要求从一个初始状态移动到一个目标状态所要花费的最少步数【算法分析】解决此类问题的办法是宽度搜索,深度搜索耗时太大无法接受。

当需要移动的步数很多时,普通的宽度搜索仍旧无法满足需要,需要对其进行优化。

这个问题也可以推广到流行的拼图游戏。

【具体步骤】一、确定问题规模(考虑搜索的时间代价)二、确定产生式规则(如果规则太多,则时间代价会很大)三、套用经典宽度搜索框架写程序三、代码和结果#include <stdlib.h>#include <stdio.h>typedef struct Node {int num[9]; //棋盘状态int deepth; //派生的深度g(n)int diffnum; //不在位的数目h(n)int value; //耗散值f(n)=g(n)+h(n)struct Node * pre;struct Node * next;struct Node * parent;}numNode; /* ---------- end of struct numNode ---------- */int origin[9]; //棋盘初始状态int target[9]; //棋盘目标状态int numNode_num,total_step;numNode *open,*close; //Open表和Close表numNode *create_numNode(){return (numNode *)malloc(sizeof(numNode));}numNode *open_getfirst(numNode *head); //返回第一项,并从Open表中删除void open_insert(numNode *head,numNode *item); //向Open表中按序插入新节点void close_append(numNode *head,numNode *item); //向Close表中插入新节点int expand(numNode *item); //扩展节点int print_result(numNode *item); //打印结果numNode *copy_numNode(numNode *orgin);char isNewNode(numNode *open,numNode *close,int num[9]);//是否在Open表或Close表中void print_num(int num[9]); //打印棋盘状态int diff(int num[9]); //求不在位棋子的个数void init(); //初始化,获得棋盘初始状态和目标状态void swap(int *a,int *b);int operate(int num[],int op);void free_list(numNode *head);/** === FUNCTION ======================================================================* Name: 主函數* Description: 程序入口*=============================================================================== ======*/intmain ( int argc, char *argv[] ){//初始化Open表和Close表open=create_numNode();close=create_numNode();open->pre=open->next=close->pre=close->next=NULL;init(); //由用户输入初始和目标状态//初始化初始节点numNode *p1;p1=create_numNode();p1->parent=NULL;p1->deepth=0;int i=0;for ( i=0; i<9; i++){p1->num[i]=origin[i];}open_insert(open,p1);numNode_num=1;p1=open_getfirst(open);while (p1!=NULL){close_append(close,p1);if(expand(p1))return EXIT_SUCCESS;p1=open_getfirst(open);}printf("No solution!\n");return EXIT_SUCCESS;} /* ---------- end of function main ---------- */voidinit ( ){while(1){printf("Please input opriginal status:\nFor example:123456780 stands for\n""1 2 3\n""4 5 6\n""7 8 0\n");char temp[10];scanf("%s",&temp);int i=0;for ( i=0;i<9 && temp[i]-'0'>=0 && temp[i]-'0'<=8; i++) {origin[i]=temp[i]-'0';}printf("Please input target status:\n");scanf("%s",&temp);int j=0;for ( j=0; j<9 && temp[j]-'0'>=0 && temp[j]-'0'<=8; j++){target[j]=temp[j]-'0';}system("cls");if ( i==9&&j==9){break;}}} /* ----- end of function init ----- */voidopen_insert (numNode *head,numNode *item){numNode *p,*q;p=head->next;q=head;while ( p!=NULL && item->value > p->value ){q=p;p=p->next;}q->next=item;item->pre=q;item->next=p;if(p!=NULL){p->pre=item;}} /* ----- end of function open_insert ----- */numNode *open_getfirst (numNode *head){numNode *p;if ( head->next == NULL ){return NULL;}p=head->next;head->next=p->next;if ( p->next != NULL ){p->next->pre=head;}p->pre=NULL;p->next=NULL;return p;} /* ----- end of function open_getfirst ----- */voidclose_append (numNode *head,numNode *item) {item->next=head->next;item->pre=head;head->next=item;if ( item->next!=NULL ){item->next->pre=item;}} /* ----- end of function close_append ----- */intexpand (numNode *p1){numNode * p2;int op=1;for ( op=1; op<=4; op++){p2=copy_numNode(p1);operate(p2->num,op);if(isNewNode(open,close,p2->num)=='N'){p2->parent=p1;p2->deepth=p1->deepth+1;p2->diffnum=diff(p2->num);p2->value=p2->deepth+p2->diffnum;if(p2->diffnum==0){total_step=print_result(p2);printf("Total step: %d\n",total_step);free_list(open);free_list(close);return 1;}else{numNode_num++;open_insert(open,p2);}}elsefree(p2);}return 0;} /* ----- end of function expand ----- */intoperate(int m[], int op){int blank;blank=0;while (m[blank]!=0 && blank<9 )++blank;if (blank==9)return 1;switch (op) {case 1: /* up */if (blank>2)swap(m+blank,m+blank-3);break;case 2: /* down */if (blank<6)swap(m+blank,m+blank+3);break;case 3: /* left */if (blank!=0 && blank!=3 && blank!=6)swap(m+blank,m+blank-1);break;case 4: /* right */if (blank!=2 && blank!=5 && blank!=8)swap(m+blank,m+blank+1);break;default : return 1;}return 0;}voidswap(int *a, int *b){int c;c=*a;*a=*b;*b=c;}numNode *copy_numNode (numNode *origin){numNode *p;p=create_numNode();p->deepth=origin->deepth;p->diffnum=origin->diffnum;p->value=origin->value;int i;for ( i=0; i<9; i++){(p->num)[i]=(origin->num)[i];}return p;} /* ----- end of function copy_numNode ----- */intdiff (int num[9]){int i,diffnum=0;for(i=0;i<9;i++)if(num[i]!=target[i])diffnum++;return diffnum;} /* ----- end of function diff ----- */charisNewNode (numNode *open,numNode *close,int num[9]) {numNode *p;int i=0;p=open->next;while ( p!=NULL ){for ( i=0; i<9; i++){if(p->num[i]!=num[i])break;}if(i==9)return 'O'; //Openp=p->next;}p=close->next;while ( p!=NULL ){for ( i=0; i<9; i++){if(p->num[i]!=num[i])break;}if(i==9)return 'C'; //Closep=p->next;}return 'N';} /* ----- end of function isNewNode ----- */voidfree_list (numNode *head){numNode *p,*q;p=head->next;while ( p!=NULL ){q=p->next;free(p);p=q;}free(head);} /* ----- end of function free_list ----- */voidprint_num (int num[9]){int i;for ( i=0; i<9; i++){printf("%d\t",num[i]);if((i%3)==2)printf("\n");}} /* ----- end of function print_num ----- */intprint_result ( numNode *item){numNode *p;int step;p=item;if(p!=NULL){step=print_result(p->parent);printf("\nStep %d:\n",step+1);print_num(p->num);return step+1;}else{return -1;}}四.实验心得这次试验让我更加深入了解了什么是人工智能,让我了解了人工智能的作用以及含义和人工智能的使用范围以及对于我们未来生活得作用的广大。

八数码难题代码与基本思路 Eight puzzles

八数码难题代码与基本思路 Eight puzzles

图搜索求解八数码算法--A*算法(步程差) 一.流程框图二.算法基本原理拓展节点并计算步程差,如果是目标节点,成功并退出,如果不是,判断是否为优质节点,是则拓展为子节点,否则舍弃;判断深度是否越界,是则失败,未越界则继续拓展节点,若拓展表为空,则失败退出。

八数码结构体由矩阵Array,步程差Value,屏蔽方向Undirect和父节点指针*parent四部分组成,Array存放矩阵数字状态,Value存放估值函数值,Undirect记录上一步移动方向避免逆推,*parent记录父子关系用于寻径。

三.模块分析Getgraph 键盘输入获得初始数码组并返回Graph结构体指针。

Printgraph 输入八数码结构体地址,打印矩阵数字状态与当前步程差。

Evaluate 输入目标矩阵与当前矩阵,计算步程差并返回值。

Move 输入当前矩阵与移动方向Direct,移动并返回新结构体地址。

Search 输入起始结构体与目标结构体,尝试寻径并记录路径并返回终点地址(若成功)或返回空指针(若失败)。

Main 主函数,定义目标矩阵并调用函数。

四.源代码// Eight-figure puzzle// A*#include"stdafx.h"#include<stdio.h>#include<stdlib.h>#define N 3 //数码组长度#define MAX 50 //最大搜索深度typedefstruct node//八数码结构体{int array[N][N];//数码组int Value;//评估值int Undirect;//所屏蔽方向,防止往回推到上已状态,1上2下3左4右struct node *parent;//父节点}Graph;Graph *Storage[MAX]; //拓展节点存储队列Graph *path[MAX]; //路径堆栈Graph *GetGraph(Graph *New_graph) ////////自定义初始数码组{int x;for (x = 0; x <N; x++){scanf("%d %d %d", &New_graph->array[x][0], &New_graph->array[x][1],&New_graph->array[x][2]);}New_graph->Value = 30;New_graph->Undirect = 0;New_graph->parent = NULL;return New_graph;}void PrintGraph(Graph *point_graph) /////////打印数码组{int i, j;if (point_graph == NULL)printf("NULL\n");else{printf(" ---------------\n");for (i = 0; i<N; i++){printf("| ");for (j = 0; j<N; j++){printf("%d ", point_graph->array[i][j]);}printf("|");if (i==N-1)printf(" Value %d ", point_graph->Value);//评估函数值printf("\n");}printf(" ---------------\n");}}int Evaluate(Graph *point_graph, Graph *End_graph) /////////评价函数{int value = 0;//评估值int i, j,m ,n ;for (i = 0; i<N; i++){for (j = 0; j<N; j++){for (m = 0; m <N; m++){for (n = 0; n <N; n++){if (point_graph->array[i][j] == End_graph->array[m][n])value = value + abs(i - m) + abs(j - n); //数字当前位置与目标位置步程差之和}}}}point_graph->Value = value;return value;}Graph *Move(Graph *point_graph, int Direct) /////////移动数码组{Graph *New_graph;int BlankLocate = 0;//定位空格指示int Movable = 1;//移动有效int i, j, x0, y0, x, y;for (i = 0; i<N; i++)//空格坐标i,j{for (j = 0; j<N; j++){if (point_graph->array[i][j] == 0){BlankLocate = 1;break;}}if (BlankLocate == 1)break;}x0 = i;y0 = j;switch (Direct){case 1://上x0--;if (x0<0)Movable = 0;break;case 2://下x0++;if (x0 >= N)Movable = 0;break;case 3://左y0--;if (y0<0)Movable = 0;break;case 4://右y0++;if (y0 >= N)Movable = 0;break;}if (Movable == 0)//不能移动则返回原节点return point_graph;New_graph = (Graph *)malloc(sizeof(Graph));//生成节点for (x = 0; x<N; x++){for (y = 0; y<N; y++){New_graph->array[x][y] = point_graph->array[x][y];//复制数码组}}New_graph->array[i][j] = New_graph->array[x0][y0];New_graph->array[x0][y0] = 0;return New_graph;}Graph *Search(Graph *Begin, Graph *End) /////////搜索函数{Graph *St1, *St2, *ta;int Step = 0;//深度int Direct = 0;//方向int i;int front, rear;front = rear = -1;//队列初始化ta = NULL;rear++;//入队Storage[rear] = Begin;while (rear != front)//队列不空{front++;//出队St1 = Storage[front];for (i = 1; i <= 4; i++)//分别从四个方向推导出新子节点{Direct = i;if (Direct == St1->Undirect)//跳过屏蔽方向continue;St2 = Move(St1, Direct);//移动数码组if (St2 != St1)//数码组是否可以移动{Evaluate(St2, End);//评价新的节点sif (St2->Value == 0)//为0则搜索完成{St2->parent = St1;rear++;Storage[rear] = St2;//存储节点到待处理队列ta = St2;break;}if (St2->Value <= St1->Value + 1){St2->parent = St1;//st2->Undirect=Direct>2?(Direct==3)+3:(Direct==1)+1;/屏蔽方向switch (Direct)//设置屏蔽方向,防止往回推{case 1://上St2->Undirect = 2;break;case 2://下St2->Undirect = 1;break;case 3://左St2->Undirect = 4;break;case 4://右St2->Undirect = 3;break;}rear++;Storage[rear] = St2;//存储节点到待处理队列}else{free(St2);//抛弃劣质节点St2 = NULL;}}}if (ta != NULL)//为0则搜索完成break;Step++;//统计深度if (Step>=MAX){break;}}return ta;}int main(int argc, constchar * argv[]){// 8 1 3 7 4 5 6 2 0// 4 1 3 2 7 5 8 0 6// 4 5 1 2 7 3 0 8 6 //16 steps in fact but failed//目标数码组Graph End_graph = {{{ 1, 2, 3 },{ 8, 0, 4 },{ 7, 6, 5 }}, 0, 0, NULL};//初始数码组Graph New_graph;Graph *Begin_graph;printf("Enter initial matrix line by line\n For example:\t1 3 4 ENTER\n\t\t8 2 5 ENTER\n\t\t7 6 0 ENTER\n\n");Begin_graph = GetGraph(&New_graph);Evaluate(Begin_graph, &End_graph);printf("Initial matrix:\n");PrintGraph(Begin_graph);printf("Target matrix:\n");PrintGraph(&End_graph);Graph *W, *P;int top = -1;//图搜索W = Search(Begin_graph, &End_graph);if (W){P = W; //压栈while (P != NULL){top++;path[top] = P;P = P->parent;}printf("<<<<<< The Path >>>>>>\n");//弹栈打印while (top>-1){P = path[top];top--;PrintGraph(P);}printf("<<<<< Mission Complete >>>>>\n");system("pause");}else{printf("Path not found ,Search depth is %d\n", MAX);system("pause");}return 0;}五.运行结果将初始数码组改写为 2 5 4 3 7 1 8 6 ,定义某个数前面比他小的数个数为Xi,所有数字的Xi相加为Y,因为四向移动只可能改变Y的大小,不改变其奇偶性。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
if(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++)//当前的状态
八数码难题
一、 问题简介 八方块移动游戏要求从一个含 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];
} int findnext(int pos,int step)//找到移动位置
{
if(step>=0&&step<4)
//四个方向移动
{
switch(step)
{
case 0:
if(isok(pos-3))
return pos-3;
return -1;
b3;1)&&pos/3==(pos+1)/3)
int hn=getallnum(); if(hn==0) {
cout<<"a solution is :"<<endl; showchar(chbak); cout<<"--第 1 步--"<<endl; showparent(thisnode); showchar(chdes);
return 1; } else
803 214 765 目标状态为: 123 804 765 二、 算法分析
1、问题表示: 问题表示的核心是如何存储搜索过程中得到的状态。本人是这样存储的:对每个状态用 一个 9 位数存储,例如: 把初始状态: 803 214 765 存储为一个 9 位数:803214765 2、问题分析 想法一:采用插入排序的方法,八数码问题好比是一列数,将各个行列的数字按大小 排列,在插入的时候考虑方向性和比较性,对每个数字节点设置前后左右四个属性,分别在 初始状态比较各自队列的大小,比如按照左前右后顺时针的方向依次比较和移动,设置哨兵, 循环比较,最后得到的序列也就是八数码问题迎刃而解了。 想法二: 采用 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+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()
if((i+1)%3==0) cout<<endl;
} } int getpath(node *thisnode,int &sums)//递归方式搜索最优路径 {
if(sums>=9*maxsize/10) {
cout<<"应该是没有解路径,需要太多空间!(需存储 "<<jiecheng(3*3)<<" 个 状 态!)"<<endl;
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()
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;
{
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]<<" ";
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); else cout<<"初始状态为目标状态!"<<endl;
相关文档
最新文档