八数码问题 题型:最小步数模型

126 阅读2分钟

845. 八数码 - AcWing题库

这道题最难的就是存储状态。

假设这个是初始状态:

1 2 3
x 4 6
7 5 8

这是最终状态:

1 2 3
4 5 6
7 8 x

我们可以把初始状态化为一维:

1 2 3 x  4 5 6 7 8

把最终状态也化为一维:

1 2 3  4 5 6 7 8 x

这样的话为我们很容易就从初始状态里找到'x'的下标,找到‘x’的下标之后我们再将这个下标转为二维下标,然后再从二维矩阵中按照这个下标与上下左右四个方向的值交换:

1 2 3   1 2 3   1 2 3   1 2 3
x 4 6   4 x 6   4 5 6   4 5 6
7 5 8   7 5 8   7 x 8   7 8 x

交换之后我们再看交换完之后的一维形式是否和最终状态的一维形式一样,一样的话说明完成了交换。

1 2 3  4 5 6 7 8 x

1 2 3  4 5 6 7 8 x

code

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int, int>PII;

int dx[] = { -1,0,1,0 }, dy[] = { 0,1,0,-1 };
int bfs(string start)
{
	
	string end = "12345678x";//最终状态
	
	queue<string> q;
	unordered_map<string, int> d;  //距离


	q.push(start);
	d[start] = 0;    //起点到起点的距离是0

	while (q.size())
	{
		auto t = q.front();
		q.pop();

		int distance = d[t]; 

		if (t == end) return distance;  //如果t是终点,那么就提前结束


		//状态转移
		int k = t.find('x');      //返回x的下标
		
		//找到x之后我们要用二维矩阵的方式来交换x与某一个位置的值
		int x = k / 3, y = k % 3;  //把一维坐标转二维坐标
	
	    //找到x之后把x的上下左右四个数移到x的位置
		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]);  //找到的(a,b)转化为一维下标



				//状态恢复
				if (!d.count(t))  //如果更新完之后的t之后没有被搜到过,说明找到新的一个点
				{
					d[t] = distance + 1;   //更新新点的距离
					q.push(t);
				}
				swap(t[k],t[a*3+b]);
			}
		}
	
		
	}
return -1;
}
void solve()
{
	string start;
	for (int i = 0; i < 9; i++)
	{
		char c;
		cin >> c;
		start += c;
	}
	cout << bfs(start) << endl;
}
int main()
{
	cin.tie(nullptr)->sync_with_stdio(false);
	int t = 1;
	while (t--)
		solve();
	return 0;
}