蓝桥杯 BFS经典题 —— 卡片换位(单走华容道)

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 思想求解

题目思想:

  1. 定位当前空格的所在位置,向四个方向一直探索
  2. 将空格与探索到的位置上的数据 互换
  3. 获取更新后的地图,并且与之前有过的地图样子相比,如若相同,则此路不行!进行下一个方向的探索
  4. 实时判断是否已经将 关羽 和 张飞互换位置了 . . .

关键点解析:

  1. 首先,准备一个类,用于标识当前的状态(空格位置、地图样子、空格移动步数):

    class Node
    {
    public:
        int currX;   	// 当前空格的所在位置
        int currY;
        string currStr; 	// 当前的字符串(地图情景)
        int currStep;  	// 当前移动了多少步
    };
  2. 方向准备(上、下、左、右):

    // 下一个方向
    int nextDirection[4][2]{
        { 0, 1 }, 
        { 1, 0 }, 
        { 0, -1 }, 
        { -1, 0 } 
    };
  3. 准备一个队列和集合容器(用于存放空格位置,判断地图是否重复):

    // 存放当前的一些数据(空格的位置、地图、步数)
    queue<Node> que;       
    
    // 判断当前的地图是否在以前存在过了(避免循环移位)
    set<string> judgeIsNoRepetition;   
  4. 探索四个方向,并且判断是否出界:

    for (size_t i = 0; i < 4; i++)
    { 
        // 获取下一步的位置
        int cx = curr.currX + nextDirection[i][0];  
        int cy = curr.currY + nextDirection[i][1];
    }
  5. 地图更新,并使用类封装新的相关数据:

    // 空格到其它位置 产生的新的地图
    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
  6. 判断地图是否存在过,避免重复:

    // 判断这个地图是否重复过 ! ! !
    if (judgeIsNoRepetition.count(tmp.currStr) != 0) continue;
    
    judgeIsNoRepetition.insert(tmp.currStr);  // 加入到集合这中
    que.push(tmp);         // 入队,继续进行下一步同样的操作

重要的步骤就上面的这些,下面是完整的代码,大家看懂之后,可以自己写一遍,^ _ ^

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码和图片的顺序一样

.

点个赞哈 !!!

浪子花梦

一个有趣的程序员 ~

  • 37
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值