洛谷6-广度优先搜索
Table of Contents
1. P1162 填涂颜色
思路:
这道题是经典的BFS
题目,用DFS
也能写,但是为了锻炼BFS
我还是坚持用BFS
。为了找出最大的被1包围的联通块,我们需要遍历每个点,用vis数组标记访问。最后没有被访问到的点就是被1包围的点,因为1的位置被限制为访问过,不会继续探索了。但这里会有一个问题,如果是边角位置的被1包围的0(即1将整个map分割成多个孤岛)我们只要中间这个完整的。可以将整个map外层裹上一层0,这样就确保了被1隔离在外面的区域一定是由0连在一起的,就能通过0访问到,而只有被1包围在里面的联通块不会被访问到。最后代码如下:
DFS
1 |
|
BFS
1 |
|
2. P1032 字串变换
思路:
常规做法是BFS搜索每个可能的解答,这里学到了一种新的做法,双向BFS。
双向BFS:
适用于知道搜索起点状态和终点状态,需要找到最短的搜索路径的情况。如果要求字典序的最短路径则不行,因为从后向前搜索的时候没办法保证字典序,只能保证最短路径。
双向BFS的时候,依次交替向前和向后迭代。当向前搜索和向后搜索的某个位置出现交叉时,此时必定是最短路径,返回结果即可。
双向bfs关键就是要记录两棵搜索树的状态,通过状态判断是否出现相遇
具体还需要通过不同的题目进行练习。
代码:
1 |
|
注意:
经常会碰到无限制输入行数的情况,此时需要使用while(cin>>a)
的句式,但是在本地编译是console是无法结束输入的,这个时候需要使用上文中注释掉的freopen
进行本地调试,在同级目录下创建对应的in.txt, out.txt
文件,将输入复制到in.txt
文件中,然后编译运行,在out.txt
文件中查看结果即可。
3. P1141 01迷宫
思路:
这道题非常有意思,如果使用经典dfs,很容易拿到70分。剩下三个case会TLE
。原因很简单就是输入样例太多。所以需要想办法保存已经搜索过的结果。最开始参考了一些题解(并查集之类的),但是还是想试试宽搜能不能做到这一点。这里有一个技巧,就是所有能跳到的位置的答案都是一样的(处于同一个联通块的答案是一样的)。因此可以设置一个flag值,表明该点属于哪一个联通块;在每次输入查询点的时候,首先看看这个查询点的flag有没有被设置为相应的联通块号码,如果有,直接输出那个联通块的答案就可以了。没有的话就进行宽搜。在宽搜的时候,我们应该想到,对于一个符合要求的点(可以跳到的位置),如果这个点已经有flag值(已经属于某个联通块),那么你马上就可以停止搜索并返回了。从main函数里每次调用dfs
的时候,就是出现了新的未在当前所有联通块里的点,这时候就应该使联通块号d++,然后对当前点进行宽搜。而宽搜的时候实际上会将属于这个联通块的所有的点都访问一遍,这个时候直接在访问的过程中设置每一个点的flag值为当前联通块号,并且将对应联通块的答案+1。
但是实际操作的时候,还是碰见了超时,因为我单独开了一个visited数组,每次输入的时候调用了memset
函数将visited清零,这个操作太耗时间了。并且,flag数组完全可以替代visited的功能,所以又修正了一下。
最后代码如下:
DFS
1 |
|
我最开始是想用BFS
的,然后才发现自己写的根本不是BFS
而是带队列的DFS
(傻傻分不清)。。。惭愧惭愧。。现在改了一个BFS
的版本补充在下方。顺带把上面的DFS
版本改了一下(DFS
要个锤子的队列。。。)
BFS
1 |
|
4. P1443 马的遍历
思路:
这道题也是经典的BFS
题目,这道题让我意识到了BFS
和DFS
两者在写法上的区别(BFS
不能递归啊××)。然后卡了的地方就是宽5格对齐,这里要使用printf
的格式化输出。printf("%-5d", &num);
代码:
1 |
|