AcWing 845. 八数码

目录

题目描述

bfs算法求解

在一个 3×3 的网格中,1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 3×3 的网格中。

例如:

1 2 3
x 4 6
7 5 8

在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 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

现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。

输入格式

输入占一行,将 3×3 的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3 
x 4 6 
7 5 8 

则输入为:1 2 3 x 4 6 7 5 8

输出格式

输出占一行,包含一个整数,表示最少交换次数。

如果不存在解决方案,则输出 −1。

输入样例:

2  3  4  1  5  x  7  6  8

输出样例

19

分析

思路就是把每种状态看成一个节点,初始的状态距离为0,每切换一个状态,到下一个状态的距离就是当前状态距离+1,求到最后一个状态节点的距离

有三个难点
  1. 状态的表示:这里使用string来表示一个状态

    1 2 3 
    x 4 6 
    7 5 8 
    

    用string表示该状态就是:"123x46758"

    最后的状态就是:"12345678x"

  2. 距离的表示:这里使用unordered_map<string, int> d 来表示到达某个状态的距离

  3. 状态转移

    对于一个状态 "t = "123x46758",首先找到x所在三维矩阵中的位置,然后在该位置上下左右四个方向进行交换得到新的状态,比如tt = "1234x6758"然后看这个状态有没有出现过(使用d.count()判断)没有出现过就将该状态的距离设置为t状态的距离+1,即d[tt] = d[t] + 1

    当转移过程中发现了end状态,就直接返回该状态的距离即可

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<unordered_map>
#include<queue> 
#include<cstring> 
using namespace std; 



int bfs(string start)
{
	string end = "12345678x"; // 结束状态 
	
	unordered_map<string, int> d; // 用来存到某个状态的距离 
	d[start] = 0;
	queue<string> q;
	
	q.push(start);
	
	// 对每一个状态,进行bfs搜索 
	while(q.size()) 
	{
		string t = q.front();
		q.pop();
		int distance = d[t]; 
		
		if(t == end) return distance; //找到了最终状态,bfs第一次发现的就是最短的路径 
		
		int k = t.find('x');
		int ax = k / 3, ay = k % 3; // 得到x在start转成三维矩阵后的坐标
		// 上下左右四个方向
		int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1};
		for(int i = 0; i < 4; i++)
		{
			int nx = ax + dx[i], ny = ay + dy[i];
			if(nx >= 0 && nx < 3 && ny >= 0 && ny < 3)
			{
				swap(t[k], t[nx * 3 + ny]);
				if(!d.count(t))  //如果这个状态没有出现过 
				{
					d[t] = distance + 1;
					q.push(t);
				} 
				swap(t[k], t[nx * 3 + ny]);
			}
		} 
	}
	
	return -1;	 
}

int main()
{
	string s, start; 
	for(int i = 0; i < 9; i++)
	{
		cin >> s;
		start += s;
	}
	
	cout << bfs(start) << endl;
	return 0;
}


时间复杂度

参考文章

上一篇:iOS --蓝牙扫描、连接、读取数据


下一篇:测开面试总结20220225