本周ACM总结之搜索篇

这周看的几乎全是搜索的,看了将近三十篇费老给的搜索例题,然后二十多篇是看的CSDN上的搜索题解,顺带看了几篇思维的题,以下便是我这周对搜索的总结。

       先说一下看了这么些搜索,总结一下我遇见的常见题型以及我学到的一些东西吧:

先是按题型分类:

第一类是从二维数组中通过将(有的和上下左右连续有的和周围八个方向连续)连续的合并找出有几块符合题意的区域(dfs、bfs、一般无回溯剪枝):这类的题一般dfs和bfs都可行,对于平常碰见的这种类型的题用哪个写难度都不大,(我还没遇见这类题过数据很大的)一般只需要搜索遍历一遍然后标记计数就可,不需要回溯和剪枝,搜索完即结束。(比如搜索0中有几堆1,用dfs 搜索到“1”时,先把它变成“0”,再看周围的有无“1”如果有就去搜索它,然后一直到找不到相邻的1,次数+1)

举一个典型的题, (这个题需要转换一下思路,和普通的题有一点不同就是没法从(1,1)向(n,n)开始搜,得从外向里搜)

从由*和0组成的二维数组中找除有多少被*包围的0

从这个题受到了一点启发,学到了一点思维,这个题看似和那些找出有几堆连续的某个符号类似但又有点不一样,在看题解之前我还在一直想怎么找到这些0,如果是一个0被包围那好判断,依次看他旁边的每个元素是不是*,但是如果同时有好几个连续的0被包围,那就不好说了,尝试写了一下也没能写对,但当我看到题解时发现这个完全就可以看做一道思维转换!!要找出被包围的0,只需要从二维数组的整个边界开始从外到内搜索,把能到达的“0”全变为“*”,这样就只剩下被包围的“0”了,再遍历找一共有几个0就行了,这也许就是换位思考吧,只要稍微转换一下思路,题就会变得简单许多,也许往大了说看题解同时也是在不断的完善自我提升自我,以后不管是在哪方面遇到困难或阻挡,也许那是的破题之解正是在这里所学到的东西

ps1:输入时如果一位数的数字是连起来的但一次只输入一个: scanf("%1d",&a[i][j]);//%1d表示只读一位(以前一直以为只有输出才能这样)

ps2:二维数组要注意数组越界问题

ps3:学到了一个小思维 从一堆二维数组中找是否有两个连续的由“*”组成的方形组成一个非方形,即在四个位置中(上2下2)若出现了三个“*”则满足

ps4:双向队列 (二维数组中一般好定义结构体,里面的变量是x,y 代表横纵坐标)deque<pp(结构体名字)>q

ps5:不用递归时可以在函数前面加inline,提高1ms的运行速度

第二类是背包问题(dfs深搜+回溯+剪枝):背包问题是找一个最优解,所以要用回溯法时对于每一个物品都有选与不选2种选择,有点类似二叉树,选或者补不选之后仍然面临两种选择。枚举所有情况,最后进行判断,如果重量不超过背包容量,且价值最大的话,这这种情况就是最优解。在这类问题中,同时也可以用剪枝避免无可能的情况,从而提高效率。对于某一个结点可能会出现目前价值加上后面数据的和仍然小于目前的最大价值的情况,就不需要再搜索下去了。

(此类问题回溯 //装入第i个物体->递归搜索第i+1个物体->剩余分支的最大值小于当前价值的最大值或.搜索完第n个物体->停止递归->回溯,去掉第i个物体)

第三类是n皇后问题(DFS深搜+回溯):因为不知道怎么找每个位置,所以需要将所有的点都试一遍,按行找或者按列找,每行(列)选择一个,若该点符合题意不冲突就深搜下一行。map[a]=b能记录一个皇后在第a行b列;判断是否在一个对角线上的方法:abs(map[v]-map[i])==abs(v-i);row[i]=true则代表这一行被占用,在进行下一次搜索后,(回溯)row[i]=false还原这一行未被占用。迷宫问题:有起点和终点的迷宫,一般要先在main主函数里输入数据的时候找到起点和终点(可用STL的map[a][b]='A'代表第a行b列是A )

第四类是全排列问题(dfs+回溯),比较简单就不多说了

(以上主要是用的dfs,接下来说几类用bfs的)

第五类是倒水问题(bfs),有几个容积固定的水壶,求准确倒出xL水所需要的最少次数。

先要用一个flag数组记录每一次的水量,bfs的终止条件即某杯中的水满足题目要求。共有六种倒水状态,可以选择map记录每次倒水前与倒水后杯中的水量(key:倒水前,value:倒水后),判断该倒水状态是否存在,若不存在将当前倒水状态加入map。

第六类是迷宫最短路径问题(bfs+剪枝),在二维数组中,有墙也有路,求起点到终点的最少步数。(注意对于相同的状态只需要处理一次就够了)在迷宫中每个点的下一条路都有很多选择,所以那些出现多次的同一个点,只入一次队列并保存即可,果断抛弃后面相同的点。
(搜索还经常和二叉树结合,但是这周还没有怎么看懂,下次看透了再说)

再按方法简单分说一下:

较小的范围,可以考虑dfs暴力枚举

回溯是在解决问题的过程中,发现有的分步答案不能得到正确答案时候,它将回溯至上一步甚至是好几步,或者是回溯至上一步寻找问题的另一个答案。这种方法有两种情况,找到一个答案但不一定是最终答案或者搜到底没有答案。

剪枝往往是用深搜遍历全部路径后,很可能会TLE超时,这时往往要用到剪枝,就是通过某种判断,避免一些不必要的遍历过程,就是如果发现这条路径不可行,就立刻回溯。上次总结了四种剪枝 这次就不想细说了:①奇偶剪枝②在搜索的时候,发现搜到一半已经不符合题目要求了,就可以提前终止退出了③在找成立的最小值时,发现现在的值已经大于目前的最优解,也可以提前终止退出了④在背包问题中,发现目前的价值加上剩下所有价值都达不到目前的最优解,那么这条路也没有意义;提前终止,而不是最后遍历完才发现不合适

可能很多人都对dfs和bfs区分不开,毕竟它俩看起来只差一个字母,以下是我对何时使用的一些想法:

二维数组的n比较小时,一般是20以内,这时用DFS基本没问题。当n再大些时甚至上百上千,一般是不能用dfs再做了(我不会可能有大佬会)

一般来说用DFS解决的问题都可以用BFS来解决,在用dfs时几乎许多题都可以用回溯和剪枝结合,只要有选或者不选,就能用回溯,剪枝并不是为了改变什么,而是提高代码的效率避免不必要的步骤。

bfs是按一层一层来访问的,所以适合有目标求最短路的步数,你想想层层搜索每次层就代表了一步。bfs优先访问的是兄弟节点,只有这一层全部访问完才能访问下一层,也就是说bfs第几层就代表当前可以走到的位置(结点).而dfs是按递归来实现的,它优先搜索深度,再回溯,优先访问的是没有访问过的子节点

dfs多用于分叉或者相连,数据位置之间有着某种关系类的问题。bfs多用于解决最短路或者最优问题,但是占用的内存空间似乎比bfs大些;dfs就像栈,bfs就像队列(几乎全是用队列实现)

本周大概就理解了这么多,因为搜索不是特别陌生所以这周看题解看起来才没有那么费劲,联系一些没学过的知识点比如二叉树比如图论的没看懂,别的都还是看懂了,但是还是有一个最核心的问题:缺少实践!!!费老说看不完就少睡觉,感觉每一天都真的在熬夜呜。在打比赛时有一个2、看着用搜索可以简单写完,但当我自以为是看着没毛病的时候,运行的时候输出的是一团乱的数字,到结束也没能找到原因,qwq~马上要回复线下了,在宿舍的时间更短更紧张了,恐怕下周进度就又要慢了,希望赶紧调整好自己的状态找到看资料和平常写别的作业时的平衡点;ACM社团要纳新了!!今晚刚交了报名表,期待面试!!!

加油!!!!!

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值