目标:
(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;
}