启发式搜索-A*算法解决八数码

目标:

(1)熟悉 A*算法的基本流程;

(2)熟悉 A*算法中的启发式函数设计方法;


实验原理

A*算法:
     创建两个表, OPEN 表保存所有已生成而未考察的节点, CLOSED 表中记录已访问过的节点。
算起点的估价值 ;
    将起点放入 OPEN ;
while(OPEN!=NULL)
{
    从 OPEN 表中取估价值 f(n) 最小的节点 n;
    if(n 节点 == 目标节点 )
        break;
   for( 当前节点 n 的每个子节点 X)
   {
        算 X 的估价值 ;
        if(XinOPEN)
        if(X 的估价值小于 OPEN 表的估价值 )
         {
                把 n 设置为 X 的父亲 ;
                更新 OPEN 表中的估价值 ;// 取最小路径的估价值
        }
        if(XinCLOSE)
                continue;
        if(Xnotinboth)
        {
                把 n 设置为 X 的父亲 ;
                求 X 的估价值 ;
                并将 X 插入 OPEN 表中 ;// 还没有排序
        }
}//endfor
    将 n 节点插入 CLOSE 表中 ; 按照估价值将 OPEN 表中的节点排序 ;// 实际上是比较 OPEN 表内节点 f 的大小,从最小路径的节 点向下进行。
}//endwhile(OPEN!=NULL)

一、初始化变量?

#include<iostream>
#include<vector>
#include<set>
#include<queue>
#include<math.h>
#include <algorithm> // std::move_backward
#include <random> // std::default_random_engine
#include <chrono> // std::chrono::system_clock
using namespace std;

#define N 3

struct Matrix { //数码矩阵
	int m[5][5];

	Matrix() {
		for (int i = 0; i < N; i++)
			for (int j = 0; j < N; j++)
				m[i][j] = 0;
	}

	bool operator<(Matrix x)const {
		for (int i = 0; i < N; i++)
			for (int j = 0; j < N; j++)
				if (m[i][j] != x.m[i][j]) return m[i][j] < x.m[i][j];
		return false;
	}
};

struct MatrixState { //移动过程状态矩阵结构体
	Matrix matrix;
	int g; //到达此状态移动的步数
	int h; //与目标状态不同的格子数

	MatrixState() {}
	MatrixState(Matrix x, int t) {
		matrix = x;
		g = t;
		h = 0;

		//int cnt = 0;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (x.m[i][j] != targetMatrix.matrix.m[i][j])
					h++;
			}
		}
	}

	bool operator<(MatrixState x)const {
		return g + h > x.g + x.h;  //按照g+h从小到大排列 
	}
}startMatrix, targetMatrix;

priority_queue<MatrixState> OPEN;
set<Matrix> CLOSED;

const int dx[4] = {-1,0,1,0};//上、右、下、左
const int dy[4] = {0,1,0,-1};

二、判断是否找到目标函数

bool isFind(MatrixState target) {
	Matrix mx = target.matrix;
	bool flag = true;
	int cnt = 0;

	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
			if (mx.m[i][j] != targetMatrix.matrix.m[i][j]) {
				flag = false;
				break;
			}

	return flag;
}

三、打印每一步搜索的状态矩阵

void printMatrix(vector<Matrix> mx,int index) {
	printf("\n");

	int n = mx.size();

	for (int i = 0; i < N; i++) {
		for (int k = 0; k < n; k++) {
			for (int j = 0; j < N; j++) {
				if(k==index) printf("\033[0m\033[1;31m%d\033[0m ", mx[k].m[i][j]);
				else printf("%d ", mx[k].m[i][j]);
			}
			printf("   ");
		}
		printf("\n");
	}
}

四、初始化输入

void init() {
	cout << "请输入初始数码矩阵:" << endl;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> startMatrix.matrix.m[i][j];
	cout << "初始数码矩阵输入完毕!" << endl << endl;
	OPEN.push(startMatrix);

	cout << "请输入目标数码矩阵:" << endl;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> targetMatrix.matrix.m[i][j];
	cout << "初始目标矩阵输入完毕!" << endl;

	printMatrix({ startMatrix.matrix },0);
}

五、产生随机输入

vector<int> RandomList() {
	vector<int> v;
	int n = (int)(pow(2, N) + 1);

	for (int i = 0; i < n; ++i) {
		v.push_back(i);
	}

	unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
	std::shuffle(v.begin(), v.end(), std::default_random_engine(seed));

	return v;
}

void initRandom() {
	cout << "随机输入初始数码矩阵:" << endl;
	vector<int> startVec = RandomList();
	int cnt = 0;

	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			startMatrix.matrix.m[i][j] = startVec[cnt++];
	cout << "初始数码矩阵输入完毕!" << endl << endl;
	OPEN.push(startMatrix);

	printMatrix({ startMatrix.matrix }, -1);

	cout << "随机输入目标数码矩阵:" << endl;
	vector<int> targetVec = RandomList();
	cnt = 0;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			targetMatrix.matrix.m[i][j] = targetVec[cnt++];
	cout << "初始目标矩阵输入完毕!" << endl;
	printMatrix({ targetMatrix.matrix }, -1);

	system("pause");

	printMatrix({ startMatrix.matrix }, 0);
}

六、主函数求解

int main() {

	int round = 0;
	bool isShow = false;

	//init(); //手动输入初始和目标
	initRandom(); //随机生成初始和目标

	while (!OPEN.empty()) {
		int x = 0;
		int y = 0;
		vector<Matrix> states;
		int sign = INT_MAX;
		int signIndex = 0;
		MatrixState mx = OPEN.top();
		OPEN.pop();

		round += 1;

		for (int i=0; i < N; i++)
			for (int j=0; j < N; j++)
				if (mx.matrix.m[i][j] == 0) {
					x = i;
					y = j;
					break;
				}

		for (int i = 0; i < 4; i++) {
			 
			if (x + dx[i] < 0 || x + dx[i] >= N || y + dy[i] < 0 || y + dy[i] >= N) continue;

			MatrixState my = mx;
			int t = my.matrix.m[x + dx[i]][y + dy[i]];
			my.matrix.m[x + dx[i]][y + dy[i]] = my.matrix.m[x][y];
			my.matrix.m[x][y] = t;

			MatrixState state(my.matrix,round);
			states.push_back(state.matrix);

			if (CLOSED.find(state.matrix) == CLOSED.end()) {
				OPEN.push(state);
				CLOSED.insert(state.matrix);
			}

			if (state.g + state.h < sign) {
				sign = state.g + state.h;
				signIndex = i;
			}

			if (isFind(state)) isShow = true;
		}

		printMatrix(states, signIndex);

		if (isShow) {
			cout <<endl<< "已找到最优解"<<endl;
			return 0;
		}
	}

	cout << endl << "无解" << endl;
	return 0;
}

七、总体代码

#include<iostream>
#include<vector>
#include<set>
#include<queue>
#include<math.h>
#include <algorithm> // std::move_backward
#include <random> // std::default_random_engine
#include <chrono> // std::chrono::system_clock
using namespace std;

#define N 3

struct Matrix { //数码矩阵
	int m[5][5];

	Matrix() {
		for (int i = 0; i < N; i++)
			for (int j = 0; j < N; j++)
				m[i][j] = 0;
	}

	bool operator<(Matrix x)const {
		for (int i = 0; i < N; i++)
			for (int j = 0; j < N; j++)
				if (m[i][j] != x.m[i][j]) return m[i][j] < x.m[i][j];
		return false;
	}
};

struct MatrixState { //移动过程状态矩阵结构体
	Matrix matrix;
	int g; //到达此状态移动的步数
	int h; //与目标状态不同的格子数

	MatrixState() {}
	MatrixState(Matrix x, int t) {
		matrix = x;
		g = t;
		h = 0;

		//int cnt = 0;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (x.m[i][j] != targetMatrix.matrix.m[i][j])
					h++;
			}
		}
	}

	bool operator<(MatrixState x)const {
		return g + h > x.g + x.h;  //按照g+h从小到大排列 
	}
}startMatrix, targetMatrix;

priority_queue<MatrixState> OPEN;
set<Matrix> CLOSED;

const int dx[4] = {-1,0,1,0};//上、右、下、左
const int dy[4] = {0,1,0,-1};

bool isFind(MatrixState target) {
	Matrix mx = target.matrix;
	bool flag = true;
	int cnt = 0;

	for(int i=0;i<N;i++)
		for(int j=0;j<N;j++)
			if (mx.m[i][j] != targetMatrix.matrix.m[i][j]) {
				flag = false;
				break;
			}

	return flag;
}

void printMatrix(vector<Matrix> mx,int index) {
	printf("\n");

	int n = mx.size();

	for (int i = 0; i < N; i++) {
		for (int k = 0; k < n; k++) {
			for (int j = 0; j < N; j++) {
				if(k==index) printf("\033[0m\033[1;31m%d\033[0m ", mx[k].m[i][j]);
				else printf("%d ", mx[k].m[i][j]);
			}
			printf("   ");
		}
		printf("\n");
	}
}

void init() {
	cout << "请输入初始数码矩阵:" << endl;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> startMatrix.matrix.m[i][j];
	cout << "初始数码矩阵输入完毕!" << endl << endl;
	OPEN.push(startMatrix);

	cout << "请输入目标数码矩阵:" << endl;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			cin >> targetMatrix.matrix.m[i][j];
	cout << "初始目标矩阵输入完毕!" << endl;

	printMatrix({ startMatrix.matrix },0);
}

vector<int> RandomList() {
	vector<int> v;
	int n = (int)(pow(2, N) + 1);

	for (int i = 0; i < n; ++i) {
		v.push_back(i);
	}

	unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
	std::shuffle(v.begin(), v.end(), std::default_random_engine(seed));

	return v;
}

void initRandom() {
	cout << "随机输入初始数码矩阵:" << endl;
	vector<int> startVec = RandomList();
	int cnt = 0;

	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			startMatrix.matrix.m[i][j] = startVec[cnt++];
	cout << "初始数码矩阵输入完毕!" << endl << endl;
	OPEN.push(startMatrix);

	printMatrix({ startMatrix.matrix }, -1);

	cout << "随机输入目标数码矩阵:" << endl;
	vector<int> targetVec = RandomList();
	cnt = 0;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < N; j++)
			targetMatrix.matrix.m[i][j] = targetVec[cnt++];
	cout << "初始目标矩阵输入完毕!" << endl;
	printMatrix({ targetMatrix.matrix }, -1);

	system("pause");

	printMatrix({ startMatrix.matrix }, 0);
}

int main() {

	int round = 0;
	bool isShow = false;

	//init(); //手动输入初始和目标
	initRandom(); //随机生成初始和目标

	while (!OPEN.empty()) {
		int x = 0;
		int y = 0;
		vector<Matrix> states;
		int sign = INT_MAX;
		int signIndex = 0;
		MatrixState mx = OPEN.top();
		OPEN.pop();

		round += 1;

		for (int i=0; i < N; i++)
			for (int j=0; j < N; j++)
				if (mx.matrix.m[i][j] == 0) {
					x = i;
					y = j;
					break;
				}

		for (int i = 0; i < 4; i++) {
			 
			if (x + dx[i] < 0 || x + dx[i] >= N || y + dy[i] < 0 || y + dy[i] >= N) continue;

			MatrixState my = mx;
			int t = my.matrix.m[x + dx[i]][y + dy[i]];
			my.matrix.m[x + dx[i]][y + dy[i]] = my.matrix.m[x][y];
			my.matrix.m[x][y] = t;

			MatrixState state(my.matrix,round);
			states.push_back(state.matrix);

			if (CLOSED.find(state.matrix) == CLOSED.end()) {
				OPEN.push(state);
				CLOSED.insert(state.matrix);
			}

			if (state.g + state.h < sign) {
				sign = state.g + state.h;
				signIndex = i;
			}

			if (isFind(state)) isShow = true;
		}

		printMatrix(states, signIndex);

		if (isShow) {
			cout <<endl<< "已找到最优解"<<endl;
			return 0;
		}
	}

	cout << endl << "无解" << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值