蓝桥杯 3.搜索
蓝桥杯 3.搜索
文章目录
- 蓝桥杯 3.搜索
- DFS回溯
- DFS剪枝
- 记忆化搜索
- 编程66-75
DFS回溯
回溯法简介
- 使用**DFS(深度优先搜索)**实现, DFS是一种遍历或搜索图, 树或者图像等数据结构的算法, 当然这个图, 树未必要存储下来(隐式处理就是回溯法)
- 搜索树一般是排列型搜索树 (总节点个数n!)和子集型搜索树(总结点个数2^n)
- DFS从起始点开始, 沿着一条路径尽可能深入的搜索, 直到无法继续为止, 然后回溯到前一个结点, 继续探索其他路径, 直到遍历完整个图或树
- DFS一般使用递归来管理节点的遍历顺序


回溯法模板
// 求1~n的全排列
int a[N];
bool vis[N];void dfs(int dep){ // 深度if(dep == n + 1){ // n层for(int i = 1; i <= n; i++){cout << a[i] << "\n";}cout << "\n";return; // 出口}for(int i = 1; i <= n; i++){ // 向下搜索// 排除不合法的路径(vis[i]是否使用过)if(vis[i]) continue;// 修改状态vis[i] = true;a[dep] = i;// 下一层dfs(dep + 1);// 恢复现场vis[i] = false;// a[dep] = 0 可以省略}
}// 这是一个排列型搜索树, 子集型搜索树跟这个类似, 就是在往下走的时候只有两条, 表示"选或不选当前的元素"
例题讲解

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 15;
ll n, ans;
// 求1~n的全排列
ll a[N];
ll vis[N][N];void dfs(int dep){ // 深度if(dep == n + 1){ // n层ans++;return; // 出口}for(int i = 1; i <= n; i++){ // 向下搜索// 排除不合法的路径if(vis[dep][i]) continue;// 修改状态for(int _i = 1; _i <= n; _i++) vis[_i][i]++;for(int _i = dep, _j = i; _i >= 1 && _j >= 1; _i--, _j--) vis[_i][_j]++;for(int _i = dep, _j = i; _i <= n && _j >= 1; _i++, _j--) vis[_i][_j]++;for(int _i = dep, _j = i; _i >= 1 && _j <= n; _i--, _j++) vis[_i][_j]++;for(int _i = dep, _j = i; _i <= n && _j <= n; _i++, _j++) vis[_i][_j]++;// 下一层dfs(dep + 1);// 恢复现场for(int _i = 1; _i <= n; _i++) vis[_i][i]--;for(int _i = dep, _j = i; _i >= 1 && _j >= 1; _i--, _j--) vis[_i][_j]--;for(int _i = dep, _j = i; _i <= n && _j >= 1; _i++, _j--) vis[_i][_j]--;for(int _i = dep, _j = i; _i >= 1 && _j <= n; _i--, _j++) vis[_i][_j]--;for(int _i = dep, _j = i; _i <= n && _j <= n; _i++, _j++) vis[_i][_j]--;}
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n;dfs(1);cout << ans << "\n";return 0;
}

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e5+9;
ll n, a[N], dfn[N], idx, mindfn; // dfn表示时间戳int dfs(int x){dfn[x] = ++idx;if(dfn[a[x]]){if(dfn[a[x]] >= mindfn) return dfn[x] - dfn[a[x]] + 1;return 0;}return dfs(a[x]);
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n;for(int i = 1; i <= n; i++){cin >> a[i];}int ans = 0;for(int i = 1; i <= n; i++){if(!dfn[i]){mindfn = idx + 1;ans = max(ans, dfs(i));}}cout << ans << "\n";return 0;
}
DFS剪枝
简介
- 将搜索过程中一些不必要的部分直接剔除掉
- 剪枝是回溯法的一种重要的优化手段
例题讲解

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e5 + 9;
ll n, a[N];
vector<int> v[N];// cnt表示队伍数量, dfs返回在cnt个队伍的情况下是否可以成功分组
bool dfs(int cnt, int dep){if(dep == n + 1){return true;}// 枚举每个人所属的队伍for(int i = 1; i <= cnt; i++){bool tag = true;for(const auto &j : v[i]){if(a[dep] % j == 0){tag = false;break;}}if(!tag) continue;v[i].push_back(a[dep]);if(dfs(cnt, dep + 1)) return true;// 恢复现场v[i].pop_back();}return false;
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n;for(int i = 1; i <= n; i++){cin >> a[i];}sort(a + 1, a + 1 + n);int ans = 0;for(int i = 1; i <= n; i++){if(dfs(i, 1)){cout << i << "\n"; break;}}return 0;
}

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6 + 9;
ll n, a[5], cnt[N], prefix[N];// cnt表示队伍数量, dfs返回在cnt个队伍的情况下是否可以成功分组
void dfs(int dep, int st, int mul, int sum){// 剪枝if(mul > 1e6) return;if(dep == 4){cnt[mul]++;return;}int up = pow(1e6 / mul, 1.0 / (4 - dep)) + 3;for(int i = st + 1; i < (dep == 3 ? sum : up); i++){dfs(dep + 1, i, mul * i, sum + i);}
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);dfs(1, 0, 1, 0);for(int i = 1; i <= 1e6; i++){prefix[i] = prefix[i - 1] + cnt[i];}ll t; cin >> t;while(t--){ll l, r; cin >> l >> r;cout << prefix[r] - prefix[l - 1] << "\n";}return 0;
}

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6 + 9;
ll n, a[5], cnt[N], prefix[N];// cnt表示队伍数量, dfs返回在cnt个队伍的情况下是否可以成功分组
void dfs(int dep, int st, int mul, int sum){// 剪枝1if(mul > 1e5) return;if(dep == n + 1){cnt[mul]++;return;}// 剪枝2int up = pow(1e5 / mul, 1.0 / (n - dep + 1)) + 3;// 剪枝3for(int i = st + 1; i < (dep == n ? min(sum , up) : up); i++){dfs(dep + 1, i, mul * i, sum + i);}
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);ll t; cin >> t >> n;dfs(1, 0, 1, 0);for(int i = 1; i <= 1e5; i++){prefix[i] = prefix[i - 1] + cnt[i];}while(t--){ll l, r; cin >> l >> r;cout << prefix[r] - prefix[l - 1] << "\n";}return 0;
}
记忆化搜索
简介
- 将搜索过程中会重复计算且结果相同的部分保存下来
- 通常使用数组或者map来进行记忆化, 下标一般和dfs的参数表对应
例题讲解
- 斐波那契数列
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6 + 9;
const ll p = 1e9 + 7;
ll n, a[N], dp[N];ll f(ll n){if(n == 1 || n == 2){return 1;}if(dp[n] != -1){return dp[n];}return dp[n] = (f(n - 1) + f(n - 2)) % p;
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);memset(dp, -1, sizeof(dp)); // 初始化为-1, 表示这个状态还没有被算过cin >> n;cout << f(n) << "\n";return 0;
}

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e3 + 9;
const ll p = 1e9 + 7;
ll n, m, k, a, b, c, d, h[N][N];
ll dx[] = {0, 0, 1, -1};
ll dy[] = {1, -1, 0, 0};int dp[N][N][2];ll inmp(int x, int y){return 1 <= x && x <= n && 1 <= y && y <= m;
}bool dfs(int x, int y, int t){if(x == c && y == d){return true;}if(dp[x][y][t] != -1){return dp[x][y][t];}for(int i = 0; i < 4; i++){int nx = x + dx[i], ny = y + dy[i];if(!inmp(nx, ny)) continue;if(!t){ // 没用过背包// 不用if(h[x][y] > h[nx][ny] && dfs(nx, ny, 0)) return dp[x][y][t] = true;// 用if(h[x][y] + k > h[nx][ny] && dfs(nx, ny, 1)) return dp[x][y][t] = true;} else { // 已经用过一次背包了// 不用if(h[x][y] > h[nx][ny] && dfs(nx, ny, 1)) return dp[x][y][t] = true;}}return dp[x][y][t] = false;
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);memset(dp, -1, sizeof(dp));cin >> n >> m >> k;cin >> a >> b >> c >> d;for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){cin >> h[i][j];}}cout << (dfs(a, b, 0) ? "Yes" : "No") << "\n";return 0;
}
编程66-75

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 1e6 + 9;
ll n, d;
pair<ll, ll> a[N];
bool vis[N];
ll dist2(ll x1, ll y1, ll x2, ll y2){return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); // 两点之间的距离的平方
}void dfs(ll x){vis[x] = 1; // 第一个人肯定传染for(int i = 1; i <= n; i++){ // 枚举n个人if(dist2(a[i].first, a[i].second, a[x].first, a[x].second) > d * d) continue; // 距离大于d的平方不会被传染if(vis[i]) continue; // 标记过的不传染dfs(i); // 继续dfs}
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n;for(int i = 1; i <= n; i++){cin >> a[i].first >> a[i].second;}cin >> d;dfs(1);for(int i = 1; i <= n; i++){cout << vis[i] << "\n";}return 0;
}


// dfs大概模板(对于二维)
ll dx[...] = ...
ll dy[...] = ...
ll dfs(ll x, ll y){ll sum = a[x][y];for(int i = 0; i < 4; i++){ll xx = x + dx[i];ll yy = y + dy[i];if(xx < 1 || xx > n || yy < 1 || yy > m) continue; // 超出边界if(vis[xx][yy]) continue; // 已经被访问过if(...) // 其他限制条件// 剩下的就是满足的vis[xx][yy] = 1;}
}
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 105;
ll n, m, a[N][N], vis[N][N];
ll dx[4] = {1, 0, 0, -1}; // 下左上右
ll dy[4] = {0, 1, -1, 0};ll dfs(ll x, ll y){ // 求(x, y)整个连通块的和ll sum = a[x][y];for(int i = 0; i < 4; i++){ll xx = x + dx[i];ll yy = y + dy[i];if(xx < 1 || xx > n || yy < 1 || yy > m) continue; // 超出边界if(vis[xx][yy]) continue; // 已经被访问过if(a[xx][yy] == 0) continue; // 0vis[xx][yy] = 1;sum += dfs(xx, yy);}return sum;
}int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> m;for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){cin >> a[i][j];}}ll ans = 0;for(int i = 1; i <= n; i++){for(int j = 1; j <= m; j++){if(a[i][j] && !vis[i][j]){ // a[i][j]不为0, 并且没有被访问, 那么就dfsvis[i][j] = 1;ans = max(ans, dfs(i, j));}}}cout << ans << "\n";return 0;
}

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll N = 105;
ll n, m, f[N];
string a, b;
struct node{ll id, x, y;
}opt[N];int main(){ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);cin >> n >> a >> b >> m;for(int i = 1; i <= m; i++){cin >> opt[i].id >> opt[i].x >> opt[i].y;}for(int i = 1; i <= m; i++){f[i] = i;}do{string qwq = a;for(int i = 1; i <= m; i++){if(opt[f[i]].id == 1){qwq[opt[f[i]].x] = ((qwq[opt[f[i]].x] - '0' + opt[f[i]].y) % 10) + '0';} else {swap(qwq[opt[f[i]].x], qwq[opt[f[i]].y]);}if(qwq == b){cout << "Yes\n";return 0;}}}while(next_permutation(f + 1, f + m + 1));cout << "No" << "\n";return 0;
}
69-75没写
相关文章:
蓝桥杯 3.搜索
蓝桥杯 3.搜索 文章目录 蓝桥杯 3.搜索DFS回溯DFS剪枝记忆化搜索编程66-75 DFS回溯 回溯法简介 使用**DFS(深度优先搜索)**实现, DFS是一种遍历或搜索图, 树或者图像等数据结构的算法, 当然这个图, 树未必要存储下来(隐式处理就是回溯法)搜索树一般是排列型搜索树 (总节点个数…...
JQD武学思想
无意识,无我,空,无形, 刚柔相济,时机, 战胜对手,克服内心。不预测结果,自发反击。 简单直接的攻击,去除一切冗余的东西。 李小龙其实反复在解释这些概念,常…...
供应链管理-谈判:分配式谈判、整合式谈判、原则式谈判
一、分配式谈判 序号要点解释1特点双方在一定资源或利益范围内进行分配,一方所得即另一方所失,因此也被称为“零和谈判”。2适用场景资源有限、关系不是关键因素,以及需要快速决策的情况。例如,在竞争对手之间,如拍卖…...
C语言递归——青蛙跳台阶问题和汉诺塔问题
一、青蛙跳台阶问题 •题目描述: 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上n级台阶总共有多少种跳法。 •问题分析: 青蛙跳台阶问题可以分成n个子问题。假设青蛙要跳上n级台阶,那么它的最后一步有两种选择&…...
relief=tk.RAISED详细介绍 relief是指定控件的边框样式
relieftk.RAISED 是在使用 Python 的 Tkinter 库创建图形用户界面(GUI)时,用于设置控件外观样式的一个参数设置,下面为你详细解释: 整体功能概述 在 Tkinter 里,relief 参数用于指定控件的边框样式&#x…...
基于ffmpeg+openGL ES实现的视频编辑工具-添加转场(九)
在视频编辑的广阔领域中,转场效果无疑是提升视频流畅性与观赏性的关键要素。巧妙运用转场,能够让不同视频片段之间的衔接更为自然,同时赋予视频独特的创意魅力。本文将深入探讨如何借助 ffmpeg 和 openGL ES 技术,在视频编辑工具中实现丰富多样的转场效果。 一、转场技术原…...
2025.2.21 日校内模拟赛总结(AC自动机, 期望,倍增)
文章目录 时间安排题解 时间安排 将近两个半小时才过 T 1 T1 T1,后面花一个半小时过了 T 2 T2 T2,最后半个小时写不出 T 3 T3 T3 暴力没有获得分数。 反思: T 1 T1 T1 这种题要敢于去猜结论打表,由于没有直接猜结论做了很长时…...
STM32的“Unique device ID“能否修改?
STM32F1系列的"Unique device ID"寄存器的地址为0x1FFFF7E8。 这个寄存器是只读的。 "Unique device ID"寄存器位于“System memory”中。“System memory”地址范围为“0x1FFF F000- 0x1FFF F7FF”。 所有STM32 MCU上都存在系统引导加载程序。顾名思义&a…...
[内网基础] 内网基础知识 —— Windows 工作组
关注这个专栏的其他相关笔记:[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01:Windows 工作组介绍 在一个大型单位里,可能有成百上千台计算机互相连接组成局域网,如果不对这些计算机进行分组,网络的混乱程度是可想而知…...
【新手初学】SQL注入之二次注入、中转注入、伪静态注入
二次注入 一、概念 二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。 二、原理 防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处…...
Deepseek存算分离安全部署手册
Deepseek大火后,很多文章教大家部署Dfiy和ollamadeepseek,但是大部分都忽略了数据安全问题,本文重点介绍Deepseek存算分裂安全架设,GPU云主机只负责计算、CPU本地主机负责数据存储,确保数据不上云,保证私有…...
单页图床HTML源码+本地API接口图床系统修复版源码
源码介绍 图床系统是一种用于存储和管理图片文件的在线服务。它允许用户上传图片文件,并生成相应的图片链接,从而方便用户在网页、社交媒体或其他平台上分享图片。 PS:源码压缩包分为两个版本,一个是调用360第三方api接口,另外一…...
XML DOM4J 三、XPath
1 什么是XPath XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointe…...
IDEA使用Maven方式构建SpringBoot项目
1、环境准备 确保你已经安装了以下工具: Java JDK(推荐 JDK 8 或更高版本) IntelliJ IDEA(推荐使用最新版本) 2、创建 Spring Boot 项目 (1) 打开 IntelliJ IDEA。 (2)…...
【SPIE出版,见刊快速,EI检索稳定,浙江水利水电学院主办】2025年物理学与量子计算国际学术会议(ICPQC 2025)
2025年物理学与量子计算国际学术会议(ICPQC 2025)将于2025年4月18-20日在中国杭州举行。本次会议旨在汇聚全球的研究人员、学者和业界专家,共同探讨物理学与量子计算领域的最新进展与前沿挑战。随着量子技术的快速发展,其在信息处…...
EMC Isilon存储节点挂掉--Journal故障问题处理
EMC isilon 的集群存储系统经常会遇到有些节点关机后无法启动,使用串口或者接上显示器去看,会看到node节点启动到下面的位置就不正常启动了。典型的console输出如下: 老的版本,OneFS 7.0版本以前的: Checking Isilon…...
掌握 ElasticSearch 组合查询:Bool Query 详解与实践
掌握 ElasticSearch 组合查询:Bool Query 详解与实践 一、引言 (Introduction)二、Bool 查询基础2.1 什么是 Bool 查询?2.2 Bool 查询的四种子句2.3 语法结构 三、Bool 查询的四种子句详解与示例3.1 must 子句3.2 filter 子句3.3 should 子句3.4 must_no…...
Spring Boot 3 集成 RabbitMQ 实践指南
Spring Boot 3 集成 RabbitMQ 实践指南 1. RabbitMQ 核心原理 1.1 什么是RabbitMQ RabbitMQ是一个开源的消息代理和队列服务器,使用Erlang语言开发,基于AMQP(Advanced Message Queuing Protocol)协议实现。它支持多种消息传递模…...
查看cmd下python的安装路径 + Windows 命令行添加环境变量和不重启刷新环境变量
1、查看cmd下python的安装路径 cmd ----》输入“python” 命令 ---》输入 import sys; print(sys.executable) 即可看到当前系统python的安装路径: 注:系统所使用的python实际上就是在系统环境变量下配置的python目录。 2、刷新path命令:在c…...
C/C++跳动的爱心
系列文章 序号直达链接1C/C李峋同款跳动的爱心2C/C跳动的爱心3C/C经典爱心4C/C满屏飘字5C/C大雪纷飞6C/C炫酷烟花7C/C黑客帝国同款字母雨8C/C樱花树9C/C奥特曼10C/C精美圣诞树11C/C俄罗斯方块小游戏12C/C贪吃蛇小游戏13C/C孤单又灿烂的神14C/C闪烁的爱心15C/C哆啦A梦16C/C简单…...
Linux 命令大全完整版(10)
4. 压缩与解压缩命令 gzip(gnu zip) 功能说明:压缩文件。语 法:gzip [-acdfhlLnNqrtvV][-S <压缩字尾字符串>][-<压缩效率>][–best/fast][文件…] 或 gzip [-acdfhlLnNqrtvV][-S <压缩字尾字符串>][-<压缩效率>][–best/f…...
Cannot deserialize instance of java.lang.String out of START_ARRAY token
这个错误 Cannot deserialize instance of java.lang.String out of START_ARRAY token 表示 Jackson 正在尝试将一个 JSON 数组反序列化成一个 String 类型的字段,但是 JSON 中传递的是一个数组而不是单一的字符串。 具体来说,这段堆栈信息:…...
一、初始爬虫
1.爬虫的相关概念 1.1 什么是爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人)就是模拟浏览器发送网络请求,接收请求响应,一种按照一定的规则,自动地爬取互联网信息的程序。 原则上,只要是浏览器…...
在低功耗MCU上实现人工智能和机器学习
作者:Silicon Labs 人工智能(AI)和机器学习(ML)技术不仅正在快速发展,还逐渐被创新性地应用于低功耗的微控制器(MCU)中,从而实现边缘AI/ML解决方案。这些MCU是许多嵌入式…...
Elasticsearch除了用作查找以外,还能可以做什么?
前言 Elasticsearch用于实时数据分析、日志存储、业务智能等。还有日志与监控、多租户和安全性。以及应用场景包括日志分析、公共数据采集、全文搜索、事件数据、数据可视化。处理错误拼写和支持变体,不过这些可能还是属于搜索优化。企业搜索、日志管理、应用监控、…...
QQ登录测试用例报告
QQ登录测试用例思维导图 一、安全性测试用例 1. 加密传输与存储验证 测试场景:输入账号密码并提交登录请求。预期结果:账号密码通过加密传输(如HTTPS)与存储(如哈希加盐),无明文暴露。 2. 二…...
《算法基础入门:最常用的算法详解与应用(持续更新实战与面试题)》
1. 排序算法 排序算法是将一组数据按特定的顺序排列起来的算法,常见的有: 冒泡排序(Bubble Sort)选择排序(Selection Sort)插入排序(Insertion Sort)归并排序(Merge So…...
单臂路由
单臂路由(Router on a Stick)是一种网络配置方式,主要用于在单个物理接口上实现多个VLAN之间的路由。它通常用于交换机与路由器之间的连接,适用于VLAN间通信需求较小的情况。 工作原理 VLAN划分:交换机上配置多个VLAN…...
细说STM32F407单片机2个ADC使用DMA同步采集各自的1个输入通道的方法
目录 一、示例说明 二、工程配置 1、RCC、DEBUG、CodeGenerator 2、USART6 3、TIM3 (1)Mode (2)参数设置 (3) TRGO (4)ADC1_IN0 1)ADCs_Common_Settings 2&a…...
[python脚本]论文1.(一)CPU/内存数据分析和分组
CPU 收集到的CPU数据,格式如下: 由于这里6个数据为一组来收集latency的数据以及各个分位值的数据,而本质上每一行都是一次完整的测试,因此这里将这个csv文件分为两个文件,第一个是和latency相关的,将6条数…...
