A*算法求解15数码问题(含详细注释解释,300行代码)

问题描述:
算法程序: 设计一个启发函数,利用A算法求解15数码问题。
要求: 尽可能用与A
算法一致的思路实现算法, 力求简单明了地给出一个解.

A*算法求解15数码问题(含详细注释解释,300行代码)_第1张图片
一、A*算法
A算法是一种常用的启发式搜索算法。 在A算法中,一个结点位置的好坏用估价函数来对它进行评估。 A*算法的估价函数可表示为: f’(n) = g’(n) + h’(n) 这里,f’(n) 是估价函数, g’(n) 是起点到终点的最短路径值,h’(n)是n到目标的最短路经的启发值。由于这个 f’(n) 无法预先知道,所以实际上使用的是下面的估价函数: f(n) = g(n) + h(n)。其中 g(n) 是从初始结点到节点 n 的实际代价, h(n)是从结点n到目标结点的最 佳路径的估计代价。在这里主要是 h(n) 体现了搜索的启发信息,因为 g(n) 是已 知的。用 f(n) 作为 f’(n) 的近似,也就是用 g(n) 代替 g’(n) ,h(n) 代替 h’(n) 。
这样必须满足两个条件:
(1)g(n)>=g’(n)且f必须保持单调递增。
(2)h 必须小于等于实际的从当前节点到达目标节点的最小耗费 h(n)<=h’(n)

二、算法实现步骤(结合本题代码)

  1. 根据已知的起两个15数码表建立初始状态结点start和目标状态结点end,计算初始状态结点的评价函数值
  2. 创建open表和close表,将初始状态结点start加入open表中。
  3. 如果open表为空,则查询失败并退出程序,否则进入步骤4
  4. 在open表中找到评价函数值最小的点(取open表的首个结点),判断是否为目标结点,如果是则代表查询成功并退出循环(程序),否则将当前结点作为待拓展结点,进入步骤5
  5. 对于待拓展结点,通过上下左右四个方向移动空格位置来拓展新状态结点,同时更新各个新状态节点的评价函数估计值,并且新状态结点记录下前一个结点下标index(为了打印最终状态路径)。
  6. 对于新拓展的结点:
    ①若新拓展的结点不在open表和close表中,则加入到open表中;
    ②若新拓展的结点在open表,如果新节点的评价函数估计值小于原有结点的评价函数估计值,则用新节点替换掉open表的旧结点
    ③若新拓展的结点在close表,如果新节点的评价函数估计值小于原有结点的评价函数估计值,则用新节点替换掉close表的旧结点
  7. 将当前拓展结点从open表中删除,加入close表中,并且对open表依据评价函数估计值进行排序,跳转到步骤3.

实现代码:

#include 
#include 
#include 
#include 
using namespace std;
#define ROW 4
#define COL 4
#define N 0     //north
#define S 1     //south
#define W 2
#define E 3

class state{
public:
    int status = 0;
	int d = 0;      //当前深度值
	int p = 0;      //与目标状态的总距离
	int f = 0;      //函数估算值
    int direction = 0;		// 记录方向
	int index;			//下标
    int pre;            //记录前一状态
    int matrix[ROW][COL];

    state(){}
    state(int matrix[ROW][COL]){		// 构造函数初始化
		memcpy(this->matrix, matrix, sizeof(int)*ROW*COL);
		//pre = NULL;
	}

    bool compare(int t[ROW][COL]) {		//判断当前矩阵状态与矩阵t是否一样
		int sum = 0;
		for(int i = 0; i < ROW; i++)
			for (int j = 0; j < COL; j++) {
				if (matrix[i][j] != t[i][j])
					return false;
			}
		return true;
	}

	void setS0(int d, int f) {          //设置起始状态的深度和评价函数估计值
		this->d = d;
		this->f = f;
	}

	void setD(int t[ROW][COL]) {	// 计算当前状态深度
		d += 1;		//深度值加1
		setP(t);
	}
	void setP(int t[ROW][COL]) {		// 计算当前状态各点与目标状态t的各点的最短距离之和
		int num = 0;
		for(int i = 0; i < ROW; i++)
			for (int j = 0; j < COL; j++) {
				for(int m = 0; m < ROW; m++)
					for (int k = 0; k < COL; k++) {
						if (matrix[i][j] == t[m][k] && matrix[i][j] != 0) {
							num += abs(i - m) + abs(j - k);
						}
					}
			}
		p = num;
		setF();			//接着设计估评价函数估计值(p+d)
	}
	void setF() {
		f = p + d;
	}

    bool operator<(const state &temp) const {
		return f < temp.f;
	}

    bool up(int t[ROW][COL]) {
		if (direction != S) {//上一步不是向下移  防止出现来回移动
			int temp;
			direction = N;//这步是向上移
			for (int i = 0; i < ROW; i++) {
				for (int j = 0; j < COL; j++) {
					if (matrix[i][j] == 0 && i - 1 >= 0) {			//在i j位置是0
						temp = matrix[i][j];
						matrix[i][j] = matrix[i - 1][j];
						matrix[i - 1][j] = temp;
						setD(t);		//设置当前状态d p f
						return true;
						break;
					}
				}
			}
		}
		setD(t);
		return false;
	}
	bool down(int t[ROW][COL]) {
		if (direction != N) {//上一步不是向上移
			int temp;
			direction = S;//这步是向下移
			for (int i = 0; i < ROW; i++) {
				for (int j = 0; j < COL; j++) {
					if (matrix[i][j] == 0 && i + 1 < ROW) {
						temp = matrix[i][j];
						matrix[i][j] = matrix[i + 1][j];
						matrix[i + 1][j] = temp;
						setD(t);
						return true;
						break;
					}
				}
			}
		}
		setD(t);
		return false;
	}
	bool left(int t[ROW][COL]) {
		if (direction != E) {//上一步不是向右移
			int temp;
			direction = W;//这步是向左移
			for (int i = 0; i < ROW; i++) {
				for (int j = 0; j < COL; j++) {
					if (matrix[i][j] == 0 && j - 1 >= 0) {
						temp = matrix[i][j];
						matrix[i][j] = matrix[i][j - 1];
						matrix[i][j - 1] = temp;
						setD(t);
						return true;
						break;
					}
				}
			}
		}
		setD(t);
		return false;
	}
	bool right(int t[ROW][COL]) {
		if (direction != W) {//上一步不是向左移
			int temp;
			direction = E;//这步是向右移
			for (int i = 0; i < ROW; i++) {
				for (int j = 0; j < COL; j++) {
					if (matrix[i][j] == 0 && j + 1 < COL) {
						temp = matrix[i][j];
						matrix[i][j] = matrix[i][j + 1];
						matrix[i][j + 1] = temp;
						setD(t);
						return true;
						break;
					}
				}
			}
		}
		setD(t);
		return false;
	}
	void show() {           //显示当前状态   并且显示对应的深度值 与目标的差距 评价函数估计值
		for (int i = 0; i < ROW; i++) {
			for (int j = 0; j < COL; j++) {
				cout << matrix[i][j] <<" "; 	
			}
			cout << endl;
		}
		cout << "d:" << d << "   " << "h:" << p << "   " << "f:" << f << endl;
		cout << endl;
	}
};

vector store;

class A_star{
public:
    vector open;
	vector close;
	state start;
	state end;
	int count = 0;

    A_star() {}

	A_star(state start, state end){         //构造函数
		this->start = start;
		this->end = end;
		this->start.setS0(-1, 0);
		this->start.setD(end.matrix);
		open.push_back(this->start);		//首状态进入open表
	}

	bool inOpen(state temp) {		// 判断是否在open表
		vector::iterator it;
		int count = 0;
		for (it = open.begin(); it != open.end(); it++) {
			if (temp.compare(it[0].matrix) && temp.f < it[0].f) {	//如果新节点在open表中 用新节点替换旧节点 IF 新节点的f值小于旧节点
				open.erase(open.begin() + count);		//删除旧结点
				open.push_back(temp);		//插入新节点
				return true;
			}
			count++;
		}
		return false;
	}
	bool inClose(state temp) {		// 判断是否在close表
		vector::iterator it;
		int count = 0;
		for (it = close.begin(); it != close.end(); it++) {
			if (temp.compare(it[0].matrix) && temp.f < it[0].f) {
				close.erase(close.begin() + count);//删除旧结点
				open.push_back(temp);//插入新节点
				return true;
			}
			count++;
		}
		return false;
	}

	state transfer(int t[ROW][COL]) {	//从起始状态开始拓展 t是最终状态的矩阵值
		while (true) {
			if (open.empty()){// open表为空查询失败
				cout<<"find error!"< print;		//储存输出路径
		print.push_back(store[index]);          //将状态路径储存
        index=store[index].pre;

        while(index!=0){                //起始状态的下标在store中对应0 因此在print数组中没有加入起始状态
            print.push_back(store[index]);          //将状态路径储存
            index=store[index].pre;
        }

        cout<<"Print steps:"<=0;i--){
            cout<<"step: "<

效果显示
A*算法求解15数码问题(含详细注释解释,300行代码)_第2张图片

你可能感兴趣的:(编程)