BFS八数码问题(C++)

21 阅读2分钟

1.广度优先搜索

先从空白格周围开始搜索,上下左右四个方向找到了可交换的位置,就把位置交换之后的状态放入队列中,再从队列中取出队头元素,重复以上步骤。

2.代码详解

#include<iostream>
#include<map>
#include<queue>
#include<stack>
using namespace std;

queue<int>Q;
map<int, int>vis;     //记录该状态是否被访问过
map<int, int>step;      //记录层数
map<int, int>parent;     //记录该状态的上一个状态
stack<int>out;
int dis[4][2] = { -1,0,0,1,1,0,0,-1 };     //左、上、右、下
int u, v;

int change(int** p, int a, int b)   //把数组矩阵转为一串数字
{
	int t = 0;
	for (int i = 0; i < a; i++)
		for (int j = 0; j < b; j++)
			t = t * 10 + p[i][j];
	return t;
}

int bfs(int** p, int a, int b)    //广度搜索
{
	//初始串 a ,结束串是 b 
	int x, y, uu;    //x,y--空格所在的行列号,uu--队头八字码状态
	Q.push(u);     //把初始状态放入队列
	vis[u] = 1;      //被访问过标记为1
	step[u] = 0;      //初始层数为0
	while (Q.size())       //队空搜索结束
	{
		uu = u = Q.front();
		Q.pop();
		if (u == v)
			return step[v];
		for (int i = a - 1; i >= 0; i--)       //把八字码状态的数字转为数组
			for (int j = b - 1; j >= 0; j--)
			{
				p[i][j] = uu % 10, uu = uu / 10;
				if (p[i][j] == 0)     //标记空格位置
					x = i, y = j;
			}
		for (int i = 0; i < 4; i++)     //空格四周搜索
		{
			int nu;
			if (!(x == 0 && i == 0) && !(y == b - 1 && i == 1) && !(x == a - 1 && i == 2) && !(y == 0 && i == 3))   //当空格所走位置合理
			{
				p[x][y] = p[x + dis[i][0]][y + dis[i][1]], p[x + dis[i][0]][y + dis[i][1]] = 0;     //交换空格位置
				nu = change(p, a, b);
				if (!vis[nu])      //若该状态没有被访问过
				{
					Q.push(nu);      //入队
					vis[nu] = 1;
					step[nu] = step[u] + 1;     //层数在上一个状态层数上加一
					parent[nu] = u;          //记录该状态的父状态
				}
				p[x + dis[i][0]][y + dis[i][1]] = p[x][y], p[x][y] = 0;      //还原空格位置继续搜索
			}
		}
	}
	return -1;
}

int main()
{
	cout << "广度搜索" << endl;
	int m, n, s, t;
	int** mau, ** mav;
	cout << "输入m*n;" << endl;
	cin >> m >> n;
	mau = new int* [n], mav = new int* [n];

	for (int i = 0; i < n; i++)
		mau[i] = new int[m], mav[i] = new int[m];

	cout << "初始状态:" << endl;
	for (int i = 0; i < m; i++)
		for (int j = 0; j < n; j++)
			cin >> mau[i][j];

	cout << "最终状态:" << endl;
	for (int i = 0; i < m; i++)
		for (int j = 0; j < n; j++)
			cin >> mav[i][j];

	u = change(mau, m, n), v = change(mav, m, n);   //变成一串数字
	s = bfs(mau, m, n);

	if (s != -1)       //返回层数
	{
		cout << "到达目标状态需要 " << s << " 步" << endl;
		t = v;
		while (t)        //把所有的父状态入栈
		{
			out.push(t);
			t = parent[t];
		}
		while (out.size())      //输出目标状态的八字码求解过程
		{
			int** o;
			t = out.top();
			out.pop();
			o = new int* [n];
			for (int i = 0; i < n; i++)
				o[i] = new int[m];
			for (int i = m - 1; i >= 0; i--)
				for (int j = n - 1; j >= 0; j--)
					o[i][j] = t % 10, t /= 10;
			for (int i = 0; i < m; i++)
			{
				for (int j = 0; j < n; j++)
					cout << o[i][j] << " ";
				cout << endl;
			}
			cout << "======" << endl;
		}
	}
	else cout << "无解" << endl;     //没有返回层数
}