BFS(宽度优先搜索)
1.定义:
-
从初始状态S开始,利用规则,生成所有可能的状态,构成树的下一层节点,检查是否出现目标状态G; 若未出现,就对该层所有状态节点,分别顺序利用规则,生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现目标状态G ; 若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开,直到出现目标状态为止。
-
如图:
-
-
值得注意的是BFS是依靠队列来进行实现,正如DFS是依靠栈,这个思想有助于我们理解算法。
-
算法分析:
- 最短路径问题:在图或网格中,求从起点到终点的最短路径,要求各边权重相同 。如在迷宫中找从入口到出口的最少步数路径,因为 BFS 是按层搜索,先访问到的节点离起点更近,满足条件时能找到最短路径。
- 层次遍历问题:对树或图进行层次遍历,像二叉树的按层遍历。通过 BFS 可依次访问每一层节点。
- 状态转移问题:状态之间存在多种转移方式,要找从初始状态到目标状态的最少转移次数等,可把状态看成节点,转移关系看成边,用 BFS 求解。
蓝桥杯真题:
青蛙跳杯子
题目描述
XX 星球的流行宠物是青蛙,一般有两种颜色:白色和黑色。
XX 星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去。
如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙。
∗WWWBBB
其中,W字母表示白色青蛙,B表示黑色青蛙,∗ 表示空杯子。
XX 星的青蛙很有些癖好,它们只做 3 个动作之一:
-
跳到相邻的空杯子里。
-
隔着 1 只其它的青蛙(随便什么颜色)跳到空杯子里。
-
隔着 2 只其它的青蛙(随便什么颜色)跳到空杯子里。
对于上图的局面,只要 1 步,就可跳成下图局面:
WWW∗BBB
本题的任务就是已知初始局面,询问至少需要几步,才能跳成另一个目标局面。
输入描述
输入为 2 行,2 个串,表示初始局面和目标局面。我们约定,输入的串的长度不超过 15。
输出描述
输出要求为一个整数,表示至少需要多少步的青蛙跳。
输入输出样例
示例
输入
*WWBB
WWBB*
输出
2
此处的问题为至少需要几步,才能跳成另一个目标局面,即为最短路径问题,以示例为例,我们可以把*WWBB作为第一层,此时步数为0,而第一层的每有多少下一个状态呢?我们可以发现它有5个字符,如果都是青蛙,那么每一只青蛙所走的下一步都是下一层的一部分,而一只青蛙可以最多有六中走法,于是我们就发现了每一层之间的联系,即将每一只青蛙可能的下一步所形成的状态之和为下一层。接下只要判断能否移动即可。
代码实现:
package qingwa; import java.util.*; public class Main { // 用字符串来表示每次都状态 static String first; static String end; static int step=0;//用来表示步数 static Queue <String>q=new <String>LinkedList(); static int arr[]= {-3,-2,-1,1,2,3}; static HashSet <String>set=new <String>HashSet(); public static void bfs() { while(!q.isEmpty()) { int size=q.size(); step++;//此处是遍历了一层加一步 for(int i=0;i<size;i++) { String t=q.poll(); if(t.equals(end)) { System.out.print(step-1);//减去一是因为从初状态加一,这会使step多算一步 return; } for(int k=0;k<t.length();k++) { char t1=t.charAt(k);//表示所在位置的字符 if(t1!='*') { for(int j=0;j<arr.length;j++) { if((k+arr[j])>=0&&(k+arr[j])<t.length()&&t.charAt(k+arr[j])=='*') { StringBuffer a=new StringBuffer(t); a.setCharAt(k, '*'); a.setCharAt(k+arr[j], t1);//交换位置 String t2=a.toString();//此时得到了下一个状态 if(!set.contains(t2)) { set.add(t2); q.add(t2); } } } } } } } } public static void main(String arg[]) { Scanner sc=new Scanner(System.in); first=sc.nextLine(); end=sc.nextLine(); q.add(first); set.add(first); bfs(); } }
代码参考了蓝桥杯上的题解,如有雷同,不是偶然
总结:BFS最常考的情况就是最短路径问题,而BFS的难处在于如何确定每一层的状态,我们不妨从头推起,开始必然是一个状态,而接下来我们要看初始状态有多少个下一步,从而作为依据来不断进行下一步的分析,值得注意的是我们需要一个容器(数组或者哈希表)来记录我们走过的情况避免重复。
我的dfs的文章:蓝桥杯中的DFS(含算法分析,蓝桥杯真题,解题思路和代码)-优快云博客
题目链接(可以测试一下自己):
还有几道蓝桥杯的dfs可以练手:
2.卡片换位 - 蓝桥云课https://www.lanqiao.cn/problems/125/learning/?page=1&first_category_id=1&second_category_id=3&tags=%E7%9C%81%E8%B5%9B,BFS&tag_relation=intersection3.扫雷 - 蓝桥云课
https://www.lanqiao.cn/problems/549/learning/?page=1&first_category_id=1&second_category_id=3&tags=%E7%9C%81%E8%B5%9B,BFS&tag_relation=intersection