八数码题解

八数码题解_第1张图片

八数码是用bfs一层一层去试探出来的,最先得到答案的也就是最优解。 

八数码题解_第2张图片

根据上面的图我们可知,答案是如何的出来的,接下来我会给出ac代码并解释。

//bfs八数码
#include
#include
#include
using namespace std;
//保存序列与对应的交换次数
unordered_map d;
int dx[4] = { -1, 1, 0, 0 }, dy[4] = { 0, 0, -1, 1 };

int bfs(string start)
{
	string end = "12345678x";
	queue q;
	q.push(start);
	d[start] = 0;
	while (q.size())
	{
		auto t = q.front();
		q.pop();
		int distance = d[t];
		if (t == end) return distance;
		//x在字符串中所在的位置
		int k = t.find('x');
		//将一维下标转化为二维下标
		int x = k / 3, y = k % 3;
		for (int i = 0; i < 4; ++i)
		{
			//将他转化为二维数组的下标
			int a = x + dx[i], b = y + dy[i];
			//判断是否满足条件
			if (a >= 0 && a < 3 && b >= 0 && b < 3)
			{
				//从二维转为一维
				swap(t[k], t[a * 3 + b]);
				//找到没有遇到过的字符串就更新
				if (!d.count(t))
				{
					d[t] = distance + 1;//交换次数增加
					q.push(t);//符合条件就入队
				}
				//恢复状态,因为可能有更好的交换方式,进行下一个方向的交换
				swap(t[k], t[a * 3 + b]);
			}
		}
	}
	return -1;
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	string start;//初始状态
	for (int i = 1; i <= 9; ++i)
	{
		char c;
		cin >> c;
		start += c;
	}
	cout << bfs(start);
	return 0;
}

首先是输入问题,因为给的输入样例中间有空格,可以用getline(cin, start)来读入,但是会把空格也读进去。所以采用临时变量来读入,这样就得到一个初始状态的字符串,此字符串从一维转化为二维是本题重要的思想。 

八数码题解_第3张图片

根据题目要求的最终状态我们可以将目标答案转化为一维的字符串end。本题需要用一个哈希表来保存序列和交换次数。先将一维转化为二维满足判断条件,再每次找到'x'就上下左右去试探,也就是加上dx[i]和dy[i] 。

然后,因为字符串是一维的,所以需要从二维转化成一维做交换,注意:更新完位置并更新到哈希表中后,一定要将交换的字符恢复现场,因为4个方向中还有其他方向没有试探呢。

还有个细节就是入队时,一定要先将一个初始值给入队,不然进不去while循环。

最后,如果跳出while循环说明没有找到返回-1。

你可能感兴趣的:(1024程序员节,算法,c++,数据结构)