推荐一个题单:kuangbin带你飞,百度就能找到,是vjudge上一个题单,由邝斌大佬整理的
专题一简单搜索全题解(附题目链接):
这份题单中有模板题,也有具备一定思维难度的题,适合我这种蒟蒻巩固基础,刷完一遍之后对搜索有了不一样的理解。刚开始学习一个算法都是从模仿模板开始,深入了解之后才明白算法的核心部分还是它的思想。
分类:
1.dfs
(回溯搜索) 棋盘问题
(递归搜索)Shuffle'm Up
2.bfs
(求最优解) Dungeon Master、Catch That Cow、Find The Multiple、Prime Path、Fire Game、Fire!、Find a way、非常可乐、Pots
(坐标的搜索)迷宫问题、Dungeon Master、Fire Game、Fire!、Find a way
(数的搜索)Catch That Cow、Find The Multiple、Prime Path
3.二进制枚举
4.判断连通块个数
(dfs,bfs均可)Oil Deposits
个人心得:
1.何谓搜索
搜索,即“寻找”,寻找解的一种方法。
搜索的具体实现就是不断去寻找下一个可能为终点的点,直到遇到终点。所以终点就是搜索结束的条件。这里的终点,可以是迷宫的出口,可以是数轴上的点(catch that cow),也可以是更为抽象的,比如某个数(find the multiple),甚至是某个状态(比如Pots中,以两个罐子中的水量为状态)。
亦或者我们以遍历为目标,那就没有什么终点了,搜索结束的条件就是没有可以继续搜索的点了。
2.什么时候可以用搜索?
下一个可能为终点的点可以由目前已经找到的点通过若干种方式递推得到,且递推的方式一般为有限个。
比如平面迷宫,可以由已得到的点进行坐标移动(四个方向各走一步)得到下一个可能为终点的点。
再比如catch that cow这题,可以由已得到的数进行三种运算规则得到下个可能为所求数的数。
再比如Pots,每个状态(指两个罐子各自的水量)可以通过之前的状态进行六种倒水操作得到。
3.搜索和枚举的区别
个人对枚举的理解:列出所有可能的情况,再进行判断找解。
搜索有些时候可以代替枚举且效率更高,因为搜索里有“方向”这个概念,可以避免大量无用的枚举。
以上次遇到的一道题为例:
完美平方数指的是每个数位上都为平方数,且其本身也是平方数的数,如:0,1,4,9,49,100……请问第n个完美平方数是?
如果采用枚举的话,就是用一个循环变量i不断加1,判断其是否为完美平方数。但这里其实做了大量无用的运算,因此耗时会非常恐怖。
而用搜索将会非常方便。这道题其实暗含了“方向”。每个数位都是平方数,那么其实也就0149四种选择,这四种选择就是四个方向。我们以1为起点,它的下一个可能的解就是10,11,14,19,再判断。这样就省去了大量无用的运算。
当然不是所有题目都可以用搜索来代替枚举的。
4.dfs与bfs的相同处(搜索的基本架构)
一般需要一个vis数组记录访问过的点以避免重复搜索。
搜索的结构:
if(找到搜索终止条件){
结束搜索;
}
else{ //继续寻找可能的点
向各个方向继续搜索;
判断搜索到的点是否有意义:
//这里意义的由自己决定,首先肯定要保证搜索到的点在数据范围内,其次判断是否是一些题目要求的不能走的点(比如迷宫里的墙,当然还可以在这里进行剪枝
if(有意义)
继续搜索
//dfs表现为继续递归搜索,bfs表现为压入队列
}
5.dfs与bfs的不同
①实现方法不同:bfs用的是队列结构,它需要储存当前的状态,因此在空间效率上不如dfs。而dfs运用的是递归,效率更高。
②求解问题类型不同:在求最优解类型的问题时bfs是更好的选择,比如求迷宫中离出口的距离。再比如上面那道求第n个完美平方数(需要按顺序求)。广搜一层层向外搜索的特性隐含了最短路的概念,而如果用深搜需要枚举出所有的路径再进行比较。dfs则可以实现回溯算法,这是bfs做不到的。当然,有很多题目用dfs和bfs都是可以做出来的。
6.搜索的本质,不拘泥于模板
理解了上述的理论,那么就会发现搜索其实没有什么模板,就像为了记录搜索的路径,可以选择用数组来进行广搜而不是队列。