八数码问题的启发式搜索方法__A*搜索

八数码问题

在3×3棋盘上,放有1到8八个数码,有1个方格是空的,空位置用0表示,对空格依次执行左移、右移、上移和下移这四个操作,使得棋盘从初始状态到目标状态。本次实验中以如下初始状态和目标状态为例:
八数码问题的启发式搜索方法__A*搜索_第1张图片

1.基本思路

本次启发式搜索是在广度优先遍历的基础上给出启发信息的搜索,然后在每一层结点中利用启发信息找一个最优结点,然后在这个最优结点的基础上再扩展下一层,重复上述操作,直到找到目标结点。
启发信息:找结点的距离dist与结点的深度dep之和最小的结点,即为当前层最优结点。
其中dist是由曼哈顿距离给出,曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。
例如:求左边结点node_up到右边目标结点的dist
八数码问题的启发式搜索方法__A*搜索_第2张图片
初设distance=0
node_up.digit[0][0]=dest.digit[0][1] distance+=|0-0|+|0-1|=1
node_up.digit[0][1]=dest.digit[1][1] distance+=|0-1|+|1-1|=1+1=2
node_up.digit[0][2]=dest.digit[0][2] distance+=|0-0|+|2-2|=2+0=2
node_up.digit[1][0]=dest.digit[0][0] distance+=|1-0|+|0-0|=2+1=3
node_up.digit[1][1]=dest.digit[1][0] distance+=|1-1|+|1-0|=3+1=4
node_up.digit[1][2]=dest.digit[1][2] distance+=|1-1|+|2-2|=4+0=4
node_up.digit[2][0]=dest.digit[2][0] distance+=|2-0|+|0-0|=4+0=4
node_up.digit[2][1]=dest.digit[2][1] distance+=|2-2|+|1-1|=4+0=4
node_up.digit[2][2]=dest.digit[2][2] distance+=|2-2|+|2-2|=4+0=4
dist_up=distance=4;
即该结点的dist=4

2. 搜索逻辑树

八数码问题的启发式搜索方法__A*搜索_第3张图片
在这个搜素树中,可以清晰的看到整个搜索过程:

注意:

移动结点中0数码时,要先定位到结点中的0数码的坐标位置(x,y),例如初始结点的0数码坐标位置(x,y)是(1,1),当然我们可以看到x>0时才能进行上移,x<2才能进行下移,y>0才能进行左移,y<2才能进行右移。
index 索引值是为了输出由初始结点到目标结点的路径而设置的

  1. 初始结点0先与目标结点对比,如果不一致则继续下列步骤,一致则开始输出。
  2. 初始结点0经过上、下、左、右移动可以扩展为结点1、2、3、4,然后再更新结点1、2、3、 4的索引 index 为上层初始结点0的下标0。即由初始第一层到第二层的扩展完成,再分别计算第二层结点的dist,再在这一层中找到 min(dist+dep) 的结点,即就是结点1为最小启发信息的结点,也就是这层的最优点。与目标结点对比,不一致则继续下列步骤。
  3. 再以结点1经过移动扩展结点:但是发现不能上移,下移之后的结点与之前的结点0有相同,左移得到结点5,右移得到结点6,所以不能归为这一层。然后再更新结点5、 6的索引 index 为上层初始结点1的下标1。再分别计算第三层结点的dist,再在这一层中找到 min(dist+dep) 的结点,即就是结点5为最小启发信息的结点,也就是这层的最优点。与目标结点对比,如果不一致则继续下列步骤。
  4. 再以结点5经过移动扩展结点:但是发现不能上移,下移之后得到结点7,不能左移,右移之后的结点与之前的结点1有相同,所以不能归为这一层。然后再更新结点7 的索引 index 为上层初始结点5的下标5。再分别计算第四层结点的dist,再在这一层中找到 min(dist+dep) 的结点,即就是结点7为最小启发信息的结点,也就是这层的最优点。与目标结点对比,不一致则继续下列步骤。
  5. 再以结点7经过移动扩展结点:但是发现上移之后的结点与结点5相同,下移之后得到结点8,不能左移,右移之后得到结点9。然后再更新结点9 的索引 index 为上层初始结点7的下标7。再分别计算第四层结点的dist,再在这一层中找到 min(dist+dep) 的结点,即就是结点7为最小启发信息的结点,也就是这层的最优点。与目标结点对比,发现一致,则开始输出。
  6. 如何输出:
    八数码问题的启发式搜索方法__A*搜索_第4张图片

2.代码附录

(这个代码是参考别人的,本人仅仅对其进行分析)


```cpp
#include 
#include 
#include 
#include
using namespace std;

const int ROW = 3;
const int COL = 3;
const int MAXDISTANCE = 10000;
const int MAXNUM = 10000;

int abs(int a)
{
	if (a>0) return a;
	else return -a;
}

typedef struct _Node{
	int digit[ROW][COL];
	int dist;   //  距离 
	int dep;    // 深度
	int index; // 索引值 
} Node;

Node src, dest;

vector node_v;   // 储存节点 

bool isEmptyOfOPEN() { //判断Open表是否空 
	for (int i = 0; i < node_v.size(); i++) {
		if (node_v[i].dist != MAXNUM)
			return false;
	}
	return true;
}

bool isEqual(int index, int digit[][COL]) {   //判断节点是否与索引值指向的节点相同 
	for (int i = 0; i < ROW; i++)
		for (int j = 0; j < COL; j++) {
			if (node_v[index].digit[i][j] != digit[i][j])
				return false;
		}
	return true;
}

ostream& operator<<(ostream& os, Node& node) {
	for (int i = 0; i < ROW; i++) {
		for (int j = 0; j < COL; j++)
			os << node.digit[i][j] << ' ';
		os << endl;
	}
	return os;
}

void PrintSteps(int index, vector& rstep_v) {  //输出步骤 
	rstep_v.push_back(node_v[index]);
	index = node_v[index].index;
	while (index != 0) {
		rstep_v.push_back(node_v[index]);
		index = node_v[index].index;
	}

	for (int i = rstep_v.size() - 1; i >= 0; i--)
		cout << "Step " << rstep_v.size() - i
		<< endl << rstep_v[i] << endl;
}

void Swap(int& a, int& b) {  //交换 
	int t;
	t = a;
	a = b;
	b = t;
}

void Assign(Node& node, int index) {   //获取节点 
	for (int i = 0; i < ROW; i++)
		for (int j = 0; j < COL; j++)
			node.digit[i][j] = node_v[index].digit[i][j];
}

int GetMinNode() {   //获取启发值最小的节点 
	int dist = MAXNUM;
	int loc;   // the location of minimize node
	for (int i = 0; i < node_v.size(); i++) {
		if (node_v[i].dist == MAXNUM)
			continue;
		else if ((node_v[i].dist + node_v[i].dep) < dist) 
		{
			loc = i;
			dist = node_v[i].dist + node_v[i].dep;
		}
	}

	return loc;
}

bool isExpandable(Node& node) {  //判断是否可扩展 
	for (int i = 0; i < node_v.size(); i++) {
		if (isEqual(i, node.digit))
			return false;
	}
	return true;
}

int Distance(Node& node, int digit[][COL]) {   //计算距离 
	int distance = 0;
	bool flag = false;
	for (int i = 0; i < ROW; i++)
		for (int j = 0; j < COL; j++)
			for (int k = 0; k < ROW; k++) {
				for (int l = 0; l < COL; l++) {
					if (node.digit[i][j] == digit[k][l]) {
						distance += abs(i - k) + abs(j - l);
						flag = true;
						break;
					}
					else
						flag = false;
				}
				if (flag)
					break;
			}
	return distance;
}

int MinDistance(int a, int b) {  //二者取小 
	return (a < b ? a : b);
}

void ProcessNode(int index)
{   //展开节点 
	int x, y;
	bool flag;
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++) 
		{
			if (node_v[index].digit[i][j] == 0)  //定位到空格位置
			{
				x = i; y = j;
				flag = true;
				break;
			}
			else flag = false;
		}
		if (flag)
			break;
	}

	Node node_up;   //上移操作 
	Assign(node_up, index);
	int dist_up = MAXDISTANCE;
	if (x > 0)  //上移x=0位于第一行,不能上移
	{
		Swap(node_up.digit[x][y], node_up.digit[x - 1][y]);
		if (isExpandable(node_up)) //如果上移之后可扩展
		{
			dist_up = Distance(node_up, dest.digit);
			node_up.index = index;
			node_up.dist = dist_up;
			node_up.dep = node_v[index].dep + 1;
			node_v.push_back(node_up);
		}
	}

	Node node_down; //下移操作
	Assign(node_down, index);
	int dist_down = MAXDISTANCE;
	if (x < 2) {
		Swap(node_down.digit[x][y], node_down.digit[x + 1][y]);
		if (isExpandable(node_down)) {
			dist_down = Distance(node_down, dest.digit);
			node_down.index = index;
			node_down.dist = dist_down;
			node_down.dep = node_v[index].dep + 1;
			node_v.push_back(node_down);
		}
	}

	Node node_left;//左移操作
	Assign(node_left, index);
	int dist_left = MAXDISTANCE;
	if (y > 0) {
		Swap(node_left.digit[x][y], node_left.digit[x][y - 1]);
		if (isExpandable(node_left)) {
			dist_left = Distance(node_left, dest.digit);
			node_left.index = index;
			node_left.dist = dist_left;
			node_left.dep = node_v[index].dep + 1;
			node_v.push_back(node_left);
		}
	}

	Node node_right;  //右移操作
	Assign(node_right, index);
	int dist_right = MAXDISTANCE;
	if (y < 2) {
		Swap(node_right.digit[x][y], node_right.digit[x][y + 1]);
		if (isExpandable(node_right)) {
			dist_right = Distance(node_right, dest.digit);
			node_right.index = index;
			node_right.dist = dist_right;
			node_right.dep = node_v[index].dep + 1;
			node_v.push_back(node_right);
		}
	}

	node_v[index].dist = MAXNUM;
}

int main() {
	int number;

	cout << "输入初始状态:" << endl;
	for (int i = 0; i < ROW; i++)
		for (int j = 0; j < COL; j++) {
			cin >> number;
			src.digit[i][j] = number;
		}
	src.index = 0;
	src.dep = 1;

	cout << "输入目标状态" << endl;
	for (int m = 0; m < ROW; m++)
		for (int n = 0; n < COL; n++) {
			cin >> number;
			dest.digit[m][n] = number;
		}

	node_v.push_back(src);

	while (1) {
		if (isEmptyOfOPEN()) {
			cout << "找不到解!" << endl;
			return -1;
		}
		else {
			int loc;   // the location of the minimize node
			loc = GetMinNode();
			if (isEqual(loc, dest.digit)) {
				vector rstep_v;
				cout << "初始状态:" << endl;
				cout << src << endl;
				PrintSteps(loc, rstep_v);
				break;
			}
			else
				ProcessNode(loc);
		}
	}
	system("pause");
	return 0;
}


 




你可能感兴趣的:(学习笔记,人工智能,c++,数据结构)