BFS 经典题,可能答案不是最优的,参考一下也是可以的 ^ _ ^
.
DFS 相关文章如下所示:
《算法笔记》—— “迷宫求解” 之 深度优先搜索(DFS)
《算法笔记》—— 图 “邻接矩阵” 的遍历(DFS、BFS)
题目:
你玩过华容道的游戏吗?
这是个类似的,但更简单的游戏。
看下面 3 x 2 的格子
+---+---+---+
| A | * | * |
+---+---+---+
| B | | * |
+---+---+---+
在其中放5张牌,其中A代表关羽,B代表张飞, * 代表士兵。
还有一个格子是空着的。
你可以把一张牌移动到相邻的空格中去(对角不算相邻)。
游戏的目标是:关羽和张飞 交换位置
,其它的牌随便在哪里都可以
。
输入格式:
输入两行6个字符表示当前的局面
输出格式:
一个整数,表示最少多少步,才能把AB换位(其它牌位置随意)
例如,输入:
* A
* * B
程序应该输出:
17
再例如,输入:
A B
* * *
程序应该输出:
12
这个题目刚开始是使用 DFS做的,但是最后答案一直不对,随后想了一下,发现 DFS是根本行不通的,因为 DFS比较深度,将 A,B互换位置的次数不可能是最少的,大家可以画个图想一想 ^ _ ^
比如下面的代码:
这是使用深搜思想(DFS)写的,我们测试过的数据如下:
我们发现最少的情况也有 36步,但其实,这个地图我们只需要 12步就可以完成 关羽 和 张飞的互换 . . .
而我们使用的最好解是使用 ——> BFS(广度优先搜索)
BFS 是将当前最近的一个数据进行处理,大家可以动手画一画,为什么是使用 BFS是最好的 . . .
下面我将详细的讲解 BFS求解 《卡片换位》 . . .
.
BFS 思想求解
题目思想:
- 定位当前空格的所在位置,向四个方向一直探索
- 将空格与探索到的位置上的数据 互换
- 获取更新后的地图,并且与之前有过的地图样子相比,如若相同,则此路不行!进行下一个方向的探索
- 实时判断是否已经将 关羽 和 张飞互换位置了 . . .
关键点解析:
-
首先,准备一个类,用于标识当前的状态(空格位置、地图样子、空格移动步数):
class Node { public: int currX; // 当前空格的所在位置 int currY; string currStr; // 当前的字符串(地图情景) int currStep; // 当前移动了多少步 };
-
方向准备(上、下、左、右):
// 下一个方向 int nextDirection[4][2]{ { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
-
准备一个队列和集合容器(用于存放空格位置,判断地图是否重复):
// 存放当前的一些数据(空格的位置、地图、步数) queue<Node> que; // 判断当前的地图是否在以前存在过了(避免循环移位) set<string> judgeIsNoRepetition;
-
探索四个方向,并且判断是否出界:
for (size_t i = 0; i < 4; i++) { // 获取下一步的位置 int cx = curr.currX + nextDirection[i][0]; int cy = curr.currY + nextDirection[i][1]; }
-
地图更新,并使用类封装新的相关数据:
// 空格到其它位置 产生的新的地图 string str = curr.currStr; // 交换位置后,产生新的地图 swap(str[curr.currX * 3 + curr.currY], str[cx * 3 + cy]); Node tmp; // 当前最新生成的数据 tmp.currX = cx; tmp.currY = cy; tmp.currStr = str; tmp.currStep = curr.currStep + 1; // 上一步 + 1
-
判断地图是否存在过,避免重复:
// 判断这个地图是否重复过 ! ! ! if (judgeIsNoRepetition.count(tmp.currStr) != 0) continue; judgeIsNoRepetition.insert(tmp.currStr); // 加入到集合这中 que.push(tmp); // 入队,继续进行下一步同样的操作
重要的步骤就上面的这些,下面是完整的代码,大家看懂之后,可以自己写一遍,^ _ ^
代码和图片的顺序一样
.