当前位置: 首页 > news >正文

保研考研机试攻略:第六章——搜索(2)

🍦🍦🍦今天我们继续来学习搜索的后半部分:深度优先搜索(DFS)、搜索剪枝技巧、终极骗分技巧等内容。我们一起加油鸭ヾ(≧▽≦*)o ~ go go go~

目录

🧊🧊🧊6.4 深度优先搜索(DFS)

🥥例题:DreamJudge 1563

🥥例题:DreamJudge 1564

🧊🧊🧊6.5 搜索剪枝技巧

什么是剪枝?

剪枝的原则?

1.可行性剪枝

2.最优性剪枝

3.记忆化搜索

4.搜索顺序剪枝

🧊🧊🧊6.6 终极骗分技巧

1、利用预处理的思想

2、暴力剪枝

3、利用贪心的思想

4、利用概率论的思想


🧊🧊🧊6.4 深度优先搜索(DFS)

深度优先搜索的实现形式就是递归,如果把递归的流程画出来,那么我们可以得到一棵递归树,其实就是一个多叉树。

BFS 和 DFS 有什么区别呢?

对于一棵二叉树,BFS 就是二叉树的层次遍历,一层一层的扩展下去;DFS 就是二叉树的中序遍历,一条路走到底,然后回溯走第二条,直到所有路都走完。

大家需要注意的是,DFS一般情况下效率不如BFS,比如求DFS中的迷宫的最短路径使用DFS就会超时。

🥥例题:DreamJudge 1563

直接用DFS模板,但是数据量大的时候会超时,如下代码:(后边会有剪枝部分的学习)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
char mpt[maxn][maxn];
int vis[maxn][maxn];
int dir[4][2] = {1, 0, 0, -1, -1, 0, 0, 1};//右下左上
int ans;
//使用深度优先搜索求解
void dfs(int x, int y, int step) {if (step >= ans) return;//一个小剪枝,当步数超过答案就不用继续if (mpt[x][y] == 'E') {//找到终点ans = min(ans, step);return;}for (int i = 0; i < 4; i++) {//上下左右四个方向int nx = x + dir[i][0];int ny = y + dir[i][1];if ((mpt[nx][ny] == '*' || mpt[nx][ny] == 'E')&&vis[nx][ny] == 0) {vis[nx][ny] = 1;dfs(nx, ny, step+1);vis[nx][ny] = 0;}}
}
int main() {int h, w;while (scanf("%d%d", &h, &w) != EOF) {if (h == 0 && w == 0) break;int sx = 0, sy = 0;memset(mpt, 0, sizeof(mpt));memset(vis, 0, sizeof(vis));for (int i = 1; i <= h; i++) {scanf("%s", mpt[i] + 1);for (int j = 1; j <= w; j++) {if (mpt[i][j] == 'S') {sx = i, sy = j;//记录起点坐标}}}ans = 99999999;dfs(sx, sy, 0);printf("%d\n", ans);}return 0;
}

🥥例题:DreamJudge 1564

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
char mpt[maxn][maxn];
int vis[maxn][maxn];
int dir[8][2] = {1,0,0,-1,-1,0,0,1,1,1,1,-1,-1,1,-1,-1};
//使用深度优先搜索求解
int dfs(int x, int y) {vis[x][y] = 1;for (int i = 0; i < 8; i++) {//8 个方向int nx = x + dir[i][0];int ny = y + dir[i][1];if (mpt[nx][ny] == '@' && vis[nx][ny] == 0) {dfs(nx, ny);}}
}
int main() {int h, w;while (scanf("%d%d", &h, &w) != EOF) {if (h == 0 && w == 0) break;int sx = 0, sy = 0;memset(mpt, 0, sizeof(mpt));memset(vis, 0, sizeof(vis));for (int i = 1; i <= h; i++) {scanf("%s", mpt[i] + 1);}int ans = 0;for (int i = 1; i <= h; i++) {for (int j = 1; j <= w; j++) {if (vis[i][j] == 0 && mpt[i][j] == '@') {ans++;dfs(i, j);}}}printf("%d\n", ans);}return 0;
}

🧊🧊🧊6.5 搜索剪枝技巧

什么是剪枝?

常用的搜索有 DFS 和 BFS。BFS 的剪枝通常就是判重,因为一般 BFS 寻找的是步数最少,重复的话必定不会在之前的情况产生最优解。深搜,它的进程近似一颗树(通常叫 DFS 树)。

而剪枝就是一种生动的比喻:把不会产生答案的,或不必要的枝条“剪掉”

剪枝的关键就在于剪枝的判断:什么枝该剪,什么枝不该剪,在什么地方减。

剪枝的原则?

正确性,准确性,高效性。

常用的剪枝有:可行性剪枝、最优性剪枝、记忆化搜索、搜索顺序剪枝。

1.可行性剪枝

如果当前条件不合法就不再继续搜索,直接 return。这是非常好理解的剪枝,搜索初学者都能轻松地掌握,而且也很好想。一般的搜索都会加上。

dfs(int x)
{if(x>n)return;if(!check1(x))return;.... return;
}
2.最优性剪枝

如果当前条件所创造出的答案必定比之前的答案大,那么剩下的搜索就毫无必要,甚至可以剪掉。我们利用某个函数估计出此时条件下答案的‘下界’,将它与已经推出的答案相比,如果不比当前答案小,就可以剪掉。

long long ans=987474477434487ll;
... Dfs(int x,...)
{if(x... && ...){ans=....;return ...;}if(check2(x)>=ans)return ...; //最优性剪枝for(int i=1;...;++i){vis[...]=1;dfs(...);vis[...]=0;}
}
//一般实现:在搜索取和最大值时,如果后面的全部取最大仍然不比当前答案大就可以返回。
//在搜和最小时同理,可以预处理后缀最大/最小和进行快速查询。
3.记忆化搜索

记忆化搜索其实很像动态规划(DP)。

它的关键是:如果对于相同情况下必定答案相同,就可以把这个情况的答案值存储下来,以后再次搜索到这种情况时就可以直接调用

还有就是不能搜出环来,不能互相依赖。

long long ans=987474477434487ll;
... Dfs(int x,...)
{if(x... && ...){ans=....;return ...;}if(vis[x]!=0) return f[x];vis[x]=1;for(int i=1;...;++i){vis[...]=1;dfs(...);vis[...]=0;f[x]=...;}
}
4.搜索顺序剪枝

在一些迷宫题,网格题,或者其他搜索中可以贪心的题,搜索顺序显得十分重要。我们经常听见有人说:“从左边搜会 T,从右边搜就 A 了”之类的话。其实在迷宫、网格类的题目中,以左上->右下为例,右下左上就明显比左上右下优秀。

在一些推断搜索题中,从已知信息最多的地方开始搜索显然更加优秀

在一些题中,先搜某个值大的,再搜某个值小的(比如树的度数,产生答案的预计(A*),速度明显会比乱搜更快。

🧊🧊🧊6.6 终极骗分技巧

有的时候题目的正解并不是搜索,由于数据范围大等原因,我们搜索不管怎么剪枝都会超时。

当你想不到正解,只会搜索的时候,千万不要气馁,我们来学习骗分技巧:

1、利用预处理的思想

这是一种中规中矩的处理方式,先将搜索过程中可能会用到的值预先处理出来,本质是用空间换时间。例如 A*(启发式搜索)就是用的这个思想,这样可以大大节约搜索时的时间开销,也能保证答案的正确性。

2、暴力剪枝

这种方法就好像一棵树上结了一个果子,你不再是每一个树枝都去寻找,而是直接砍掉一些树枝不要,然后再在剩下的树上寻找,很明显这种方法不能保证一定正确,但是却可以大大减少时间的消耗,也可以变成递归到多少层就不继续往下递归了,不管是否后面有没有果子。

3、利用贪心的思想

贪心是一种很简单的思想,虽然贪心不一定是正确,但是却有可能正确。

4、利用概率论的思想

我们都知道现在图像识别已经进入了大家的生活,但是识别不是都能 100%的准确,现在看各个厂家的产品都是说识别率能达到百分之多少,而不是 100%。那么我们可以根据对应的题目去解析几个特征值,然后设置一下概率来触发搜索的条件。

后面三种的使用效果要看各人的天赋,毕竟是绝招嘛,一般情况下不会使用的。(本质上都是利用了考研的机试题目一般都不会特别强的弱点。)

创作不易,点个赞吧~点赞收藏不迷路,感兴趣的宝子们欢迎关注该专栏~

勤奋努力的宝子们,学习辛苦了!宝子们可以收藏起来慢慢学哦~🌷🌷🌷休息下,我们下部分再见👋( •̀ ω •́ )✧~

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • docker映射了端口,宿主机不生效
  • 鸿蒙内核源码分析(共享内存) | 进程间最快通讯方式
  • SpringBoot集成kafka-获取生产者发送的消息(阻塞式和非阻塞式获取)
  • 1111111111
  • 微服务:网关路由和登录校验
  • 计算机视觉与视觉大模型对板书检测效果对比
  • 上线eleme项目
  • 怎么整合spring security和JWT
  • 【Unity3D小技巧】Unity3D中实现FPS数值显示功能实现
  • CSS 的了解text-rendering属性
  • 大模型学习笔记 - LLM 之 LLaMA系列(待更新)
  • 缺失ffmpeg.dll要用什么修复方法?快速恢复丢失的ffmpeg.dll文件
  • C++基础面试题 | C和C++的区别?
  • 【小趴菜前端学习日记3】
  • 【速览】计算机网络(更新中)
  • ➹使用webpack配置多页面应用(MPA)
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • docker容器内的网络抓包
  • ECMAScript6(0):ES6简明参考手册
  • ERLANG 网工修炼笔记 ---- UDP
  • Java 23种设计模式 之单例模式 7种实现方式
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • javascript面向对象之创建对象
  • PaddlePaddle-GitHub的正确打开姿势
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • Rancher-k8s加速安装文档
  • SQLServer之创建显式事务
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • 给新手的新浪微博 SDK 集成教程【一】
  • 构建工具 - 收藏集 - 掘金
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 基于游标的分页接口实现
  • 技术:超级实用的电脑小技巧
  • 解析带emoji和链接的聊天系统消息
  • 前端_面试
  • 设计模式(12)迭代器模式(讲解+应用)
  • 突破自己的技术思维
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 译米田引理
  • puppet连载22:define用法
  • 小白应该如何快速入门阿里云服务器,新手使用ECS的方法 ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​queue --- 一个同步的队列类​
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • (1)(1.13) SiK无线电高级配置(五)
  • (2015)JS ES6 必知的十个 特性
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • (力扣)循环队列的实现与详解(C语言)
  • (每日一问)基础知识:堆与栈的区别