八数码问题——A*搜索

本文介绍了如何使用A*搜索算法解决八数码问题。在控制台中展示矩阵,手动打乱后通过程序复原。A*算法通过结合节点深度g(x)和错位数字数h(x)作为评价函数,有效地减少了搜索空间。文章包含评价函数封装的类及相关操作如状态节点、最终状态判断和初始状态打乱等。
摘要由CSDN通过智能技术生成

先把问题简化一下吧:

在控制台显示这样一个矩阵

[1][2][3]
[8]   [4]
[7][6][5]

手动把它打乱,然后让程序将其复原。

和野人传教士问题类似,这也是一个对解空间进行搜索的问题,而且更为简单,这次采用可以缩减扩展节点的规模的A*启发式搜索算法。取节点深度为g(x),错位的数字数为h(x),由于问题很简单,所以与有序搜索算法类似,算法框图:

 评价函数封装在类里,所以没显示在框图中。

ElemType类包括了对于状态节点所需的所有操作:显然的,用一个一维数组maze[9]保存这九个位置的数,评价函数evaluate()函数返回当前状态的评价值,对节点进行操作的运算符">>",判断是否是最终节点的isSuccess(),以及打乱初始节点的顺序的disrupt()等等。

#include <iostream>

#include <conio.h>

#include <windows.h>     //显示矩阵时需要延时,这里有Sleep()函数。

using namespace std;

 

//接收键盘时使用

const enum Input { UP = 0x048, DOWN = 0x050, LEFT = 0x04b, RIGHT = 0x04d, ENTER = 0xd };

//扩展时判断方向使用

const int U = 0;

const int D = 1;

const int L = 2;

const int R = 3;

 

class ElemType {

private:

    int depth;        //当前节点的深度(就是距离初始节点有多远)

    int numWrong();   //有多少错位的数字

 

public:

 

    int maze[9];      //保存矩阵用

    ElemType* flag;   //指向根节点

    ElemType();       //创建初始节点

 

    ElemType(int,int,int,int,int,int,

include using namespace std; struct node{ int nodesun[4][4]; int pre; //上一步在队列中的位置 int flag ; //步数标识,表示当前的步数为有效的 int value; //与目标的差距 int x,y; //空格坐标 }queue[1000]; //移动方向数组 int zx[4]={-1,0,1,0}; int zy[4]={0,-1,0,1}; //当前步数 int top; int desti[4][4];//目标状态 int detect(struct node *p)//检查是否找到 {int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) return 0; return 1; } //打印 void printlj() {int tempt; int i,j; tempt=top; while(tempt!=0) { for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<queue[tempt].nodesun[i][j]; if(j==3) cout<<" "<<endl; } tempt=queue[tempt].pre; } } //现在状态与目标状态有多少个不同位置 int VALUE(struct node *p) {int count=0; int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) count++; return count; } void main() { //初始化 int i,j,m,n,f; int min=10; int temp,find=0,minnumber; top=1; for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; queue[1].nodesun[i][j]=temp; } cout<<"请输入初始状态的空格的位置(行)"<>temp; queue[1].x=temp; cout<<"请输入初始状态的空格的位置(列)"<>temp; queue[1].y=temp; queue[1].value=VALUE(&queue[1]); queue[1].pre=0; //上一步在队列中的位置 queue[1].flag=0; //目标状态 for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入目标状态第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; desti[i][j]=temp; } //根据估价函数 while(!find&&top>0) { for(i=1;i<=top;i++) //////////////////////////////////////////// //min为上一中与目标有多少个元素不相同,queue[i]为当前与目标有多少个元素不相同通过这两个数的比较,就可以得出当前较之上一向目标接近同时把当前的i记录下来进行下一步比较 {if(queue[i].value<min&&queue[i].flag==0) {minnumber=i;// min=queue[i].value; //还有多少不同的位数 } } queue[minnumber].flag=1; //表示此位有效 ////////////////////////////////////// // for(f=0;f=1&&i=1&&j<=3) {top++; ///////////////////////////////////////////// //位置交换 queue[top]=queue[minnumber]; queue[top].nodesun[m][n]=queue[minnumber].nodesun[i][j]; queue[top].nodesun[i][j]=0; /////////////////////////////////////// //空格移动方向 queue[top].x=i; queue[top].y=j; /////////////////////////////////////// queue[top].pre=minnumber; //上一步在队列中的位置 queue[top].value=VALUE(&queue[top]); //有多少位与目标不同 queue[top].flag=0; //标识位初始化 if(detect(&queue[top])) //检查是否为目标 {printlj(); //打印 find=1; //设找到标识位 break; } } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值