wp_图论与搜索
图论与搜索
DFS 深度优先搜索
用途:枚举、路径搜索、连通性。
常见坑:注意回溯还原(如标记数组清零),加剪枝防超时。
小猫爬山
1 | int n, w, ans = 20; |
复杂度:O(2^n) 最坏,剪枝后更优。
BFS
P1434 [SHOI2002] 滑雪
- 链接: 题目链接
- 算法类型: 拓扑dp
- 此为标准代码请认真研读
- AC 代码:
1 | vi dr = {1, 0, -1, 0}; |
- 思路:
-
- 建图(这里用反图更方便)
- 2.\ 计算入度
- 3.\ 入度为0的点入队
- 4.\BFS:
- 5.\ 答案 = max(dp[])
-
1 | //BFS |
- 注意事项:
- 记得BFS不要漏了
bool visit数组 - 记得BFS状态转移(?)方程
mp[hsh][ljl] = mp[h][w] + 1; - 最短路问题 不是“另一种算法”,它就是 DP 在无权图上的高效实现
- 记得BFS不要漏了
- 改进思路:
- 考虑严格 cnt == k 的情况,调整 check 函数。
P1825 [USACO11OPEN] Corn Maze S
- 题号: P1825
- 链接: 题目链接
- 算法类型: BFS
- 记录原因:
- AC了,终点看引参数进数组!不要天天被神秘UB卡住脑子
- 这道题无非是标准BFS上面加了个规则函数:这道题放这里就是教你如何写有规则的搜索
- AC 代码:
1 | void goincsm(const vector<vector<int>> &mp, int &xx, int &yy) |
- 注意事项:
- 取地址代表可更改
int &xx:适用于那些总是要更改的量 const vector<vector<int>> &mp既安全又高校的传图方式
- 取地址代表可更改
P2895 [USACO08FEB] Meteor Shower S
- 题号: P2895
- 链接: 题目链接
- 算法类型: BFS
- 错误原因:
- 边界检查边界检查边界检查
- 时间更新逻辑
- vis数组限制逻辑(依旧时间更新逻辑)
- AC 代码:
1 | vi dx = {-1, 0, 1, 0}; |
- 注意事项:
- 注意:这道题没有规定地图大小,对于流星影响(限制点)最大可到301*301.所以我们的搜索应该开到303(最保险),包括continue地搜索限制
- 注意time更新逻辑:lily只能在ti之前到达这个点,所以对于每个影响的点需要参考的是time+1;
- 注意bfs每层地更新逻辑:每次入队都是time(i)时间点可到地所有点
- 结构体lambda搜索技巧:
1 | 根据ti寻找bar中所需要地项,返回迭代器 |
P1162 填涂颜色 提供深搜广搜两种做法
- 题号: P1162
- 链接: 题目链接
- 算法类型: 搜索板子
- 错误原因:
- 注意从四周寻找‘0’切入
- AC 代码广搜版:
1 | vector<vector<int>> mp(35, vi(35)); |
- AC 代码深搜版:
1 | void dfs(int a, int b, vector<vector<int>> &mp) |
- 注意事项:
- 注意从四周引入点
- 注意入队时机
- 改进思路:
- 学习两种搜索方式
3.2 无向图分组
用途:求连通分量数。
常见坑:双向边需存两次,初始化标记数组。
1 | vector<vector<int>> a(2e5 + 10); |
复杂度:O(n+m),空间 O(n+m)。
图论:常见做法:反向建边
P4017 最大食物链计数(拓扑排序)
- 题目概述 给出一张有向无环图,求出最长路径的数量(最长路径定义:入度为0的点到初读为0的点),n是节点数量,m是路径数量
- 数据范围:n:2e3,m:1e5
- 初始思路 ;记忆化加DFS
- 正解思路:DFS+DP
- AC代码
1 | int mod = 80112002; |
- AC代码:拓扑排序
1 | void solve() |
- 拓扑排序的目标是将所有节点排序,使得排在前面的节点不能依赖于排在后面的节点。
- 作用:
- 确定任务执行顺序
- DAG 上的动态规划
- 检测环路:如果拓扑排序无法将所有节点都加入到最终的序列中(
- **“顺序”、“依赖”、“先决条件”,或者需要在一个有向图中进行基于依赖的计算(如 DP)时
图论:dijkstra
简单 Dijkstra 模板题
P4779 【模板】单源最短路径(标准版)
- 题号: P4799
- 链接: 题目链接
- 算法类型: 图论模板
- AC 代码:
1 | void solve() |
- 注意事项:
- 注意Dijkstra算法用最小堆优化可以时间复杂度最低
- Dijkstra算法只能处理非负权路径问题
- 为什么不用队列?:贪心最快,如果是菊花图复杂度会退化到nm
- 含负权路用什么算法?用队列
- 思路:
- 认真研读并学习114514次
水群
- 题号: D
- 链接: 题目链接
- 算法类型: Disjkstr最短路
- 错误原因:
- 看成DP了!!有向无环有向无环有向无环!
- 迪克算法还在追我
- 最短路问题
- AC 代码:
1 | void solve() |
- 思路:
- 没什么好说的,迪克算法模板,我都懒得贴出代码,详情请见[简单 Dijkstra 模板题]<#p4779-模板单源最短路径标准版>
代号N
精简题干: 定义一棵树:共n个节点:一个度数为3的节点,若干个度数为2的节点,3个度数为1的节点.给出n-1条边,给出两个端点以及边权,可以操作k次将某条边边权变成0.求根节点到叶节点的度数最大值的最小值.
- AC 代码:
1 | struct edge |
- 思路剖析:
- 非常简单的大数据和的最大值的最小值.解法一:
sort之后逐个pop_back()(注意vector的pop是最后一位,所以要从小到大排序).解法二:维护最大根堆priority_queue<int>,n次操作复杂度nlogn. - 事实上解法一是优解,但是为了学习这个有意思的容器这道题用的做法是最大根堆
- 这道题的难点是读懂题…然后是建带权无向图…依旧模板.
- 记得带权无向图两个端点都pushback一次
- 然后就是用bfs带着上一个节点和下一个节点广度优先探索(这个还能用dfs解法,下文附上,作为图论路径转移学习,请严肃学习114514次)
- 非常简单的大数据和的最大值的最小值.解法一:
大部分图论用BFS做,在面临剪枝需求/需要回溯/所有方案的时候用DFS做
-
细节注意:
- 二维拓展数组记得这样开
vector<vector<edge>> mp(n + 1);不会爆空间 - Cpp17不支持结构体取地址,就这么写
auto [now, par] = pos.front(); - 记得k次操作不一定用玩一定要提前出循环
if (pq[idx].empty()) break;以免UB
- 二维拓展数组记得这样开
-
新结构
priority_queue: 自动维护堆的“插入+弹出最大/最小”工具,“贪心/最短路/Top-K/滑动窗口最大值” 都能靠它快速实现- 注意优先队列没办法删除除了堆顶以外的元素,所以注意
if (d > dist[u]) continue;
tarjan
图的遍历(tarjan算法)
-
题目描述:给出一张有向图(不保证无环),节点编号1到n,求每个节点能到达的最大编号
-
错误解法:我一开始想到的:dfs加记忆化,从入度为0的点开始dfs到出度为0的点,每个点的答案在确认的时候和自己还有其他的路径比较一下;
- 错解中的逻辑问题
- 只D入度为0的点,但是当图中出现环就会漏掉
- 为了剪枝设计了vis数组来标记有没有被访问过,但是没有重置:这个题目不保证无环,所以必须重置,甚至说这个vis的存在就没啥必要
- 在有环图中,当 DFS 访问到一个正在递归栈中的点时,说明遇到了环。正确的 DFS 应该使用三态
- 在ans中要先初始化ans[i]=i,因为每个点都可以到达自己。以免出现没有连通的点
- 错解中的逻辑问题
vis在以下情况不需要重置:当你的图是有向无环图 (DAG).或者你对每个点的计算结果是确定的、最终的、且不会随起点变化时,你可以设置 vis 后不再变回
当他作为强连通分量 (SCC) 标记也可以不重置
比如说在这道题里面,当你反向建图让他从最大数字的点开始DFS的时候vis就可以选择不重置:因为N在这条路径上是最大的点,后面的状态可以通过继承前面的状态来确定答案
-
正解一:反向建图:原理:贪心保证剪枝成功(一旦一个点的答案 被确定,它就是正确的最大值,且永远不需要重新计算。)
- 问题: 为什么 可以永不重置?
- 思考: 当我们从 开始 DFS 时,如果 还没有 ,我们就设 。在此之前,所有的 都没有在 中到达 (否则 早就被标记了)。因此,没有比 更大的点是 可达的。
-
正解二:tarjan算法:求“缩点”操作的高效算法
- 缩点然后顺序dfs+dp。求完强连通分量可以保证图片是DAG
-
检查自己方案合理性的思考路径:
- 1.\ 图的特性:有向?无环?连通性?(有没有孤立的点)边权?(负权边?)
- 2.\ 做法检验:有没有环?依赖顺序是什么?状态是否能持久?(影响剪枝)(在 DAG 上,从拓扑序逆序(即从终点开始)计算是可靠的。原图 DFS 依赖于子问题的答案,必须确保子问题先被计算。)
-
AC正解1(反向图思路)
1 | void dfs(int a, int f, const vector<vi> &mp, vi &ans) |
- AC正解2(Tarjan思路)
1 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 ZuesHans's little bag!









