
深搜dfs与广搜bfs
文章平均质量分 64
详细讲解普及组的深搜和广搜思路及剪枝等
Alice-柯
程序媛
展开
-
[NOIP2017]棋盘 深度优先搜索
如果当前需要花费的价值超过当前结点最少需要花费的钱,那么就直接停止搜索,否则把当前结点的最小价值更新。时,上一次是无色的即下一次不可以再走无色的了,否则是有色的即下一次可以走无色的。先初始化图中所有点的最低成本为0x3f3f3f3f。我在存图中,记录无色为0,红色为1,黄色为2。分别遍历当前结点上下左右可以走到的节点。原创 2022-10-06 09:09:18 · 260 阅读 · 0 评论 -
[NOIP2014]寻找道路与[NOIP2009]最优贸易 搜索
挨个遍历u能到达的结点,其中如果vis[v]的这个条件其实可有可无,因为前面都判断了u的所有子节点包括v都符合不需要可行性剪枝了。每当找到一个节点,如果当前结点为终点,则当前就是最短路,u=t时必然满足条件1,因为任何一个它的边,都能直接到达终点t。最优性剪枝:如果当前访问过,且有花最少的钱买到水晶球走到现在这一个节点的结果,直接将当前位置的最优答案更新。表示要买u前面的最便宜的地方的在后续卖钱,其中&val[u]$表示要买u编号的买在后面卖钱。挨个查找终点能直接或间接到达的编号,其中如果编号为。原创 2022-10-05 19:58:16 · 423 阅读 · 0 评论 -
DAG(有向无环图)上的动态规划
动态规划最重要的是要找到一个情况的所有子情况,处理完所有子情况后把结果通过一定的方式转移得到这个情况的答案。那么很多时候我们会遇到或者可以构造出这样一个图,每个点是一种情况,每条边代表着这条边的终点是起点的一个子情况。首先这个图是有向的,如果他里面没有环,我们称之为有向无环图(DAG),我们可以在这个图上通过状态转移的到最后的答案。接下来我们考虑如何进行动态规划的状态转移。其实,想到一个合理的转移顺序不太容易,不妨尝试用记忆化搜索的方法来做,因为是无环的,每条路径一定会到达一个终点,不会陷入无尽的环原创 2022-06-22 17:35:40 · 633 阅读 · 0 评论 -
双向广度优先搜索bfs
还有一类广度优先搜索的题目会在数字的扩展和搜索上,我们假设需要从起始状态到达目标状态需要40步,每次扩展最多产生2种状态,那么最差情况下,状态数量会到达2402^{40}240。很明显,如果我们不使用一些措施,我们的队列中必然无法存储如此多的情况,最终导致空间超限。有没有什么好的解决办法呢?其实很容易能想到,我们可以从起始状态和目标状态一起开始搜索,类似于多起点BFS。一般我们有两种方案完成双向广度优先搜索,一种类似于多起点BFS,但是在记录状态时将其分开,一旦从一端搜到已经被另一端访问过的元素,那么我原创 2022-05-30 22:32:31 · 308 阅读 · 0 评论 -
BFS中需要表示的状态
在一些问题中,我们会较难地对状态表示,此时,我们需要进行决策(或者说可以移动的动作)结合在一起。状态和决策互相配合,一旦在某个状态下有合法的决策,那么状态就必然发生变化。以《华容道》一题为例,其具体操作规则为:在一个n×m 棋盘上有n×m 个格子,其中有且只有一个格子是空白的,其余 n \times m-1n×m−1 个格子上每个格子上有一个棋子,每个棋子的大小都是 1×1 的;有些棋子是固定的,有些棋子则是可以移动的;任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白格子上。游戏的原创 2022-05-28 08:32:28 · 202 阅读 · 0 评论 -
深度优先搜索奇偶性剪枝
我们先来看一道题目:有一个n×m 大小的迷宫。其中字符’S’表示起点,字符’D’表示出口,字符’X’表示墙壁,字符’.‘表示平地。你需要从’S’出发走到’D’,每次只能向上下左右相邻的位置移动,并且不能走出地图,也不能走进墙壁。每次移动消耗 1 时间,走过路都会塌陷,因此不能走回头路或者原地不动。现在已知出口的大门会在 T 时间打开,判断在 0 时间从起点出发能否逃离迷宫。数据范围 n,m≤10,T≤50。只有从起点往终点搜,步数恰好等于T时,才能成立。我们只需要DFS来搜索每条路线,并且只需要搜原创 2022-05-21 22:20:52 · 417 阅读 · 0 评论 -
bfs广度优先搜索的标记策略与康托展开
在之前的问题中,将已到达的状态使用布尔数组或整数数组进行标记,从而避免重复访问以及得到最小步数等。当一道题的数据范围过大,例如vis数组已经需要开到甚至10^9时,为解决这样的情况带来的问题。一个很显然的方案,可以通过set或map数据结构来标记当前已经访问的位置。对于上面的问题,直接创建map<int,int> mp来标记访问的数字和对应的最小步数。另外在一些时候,需要创建结构体放入set或map中,然而直接将自建类型作为该数据结构的类型是会报错的。这是由于set和map都是基于二叉排序原创 2022-05-28 07:39:28 · 221 阅读 · 0 评论 -
深度优先搜索可行性剪枝
我在前面的文章中提到过搜索过程中最后会生成一棵搜索树。剪枝,顾名思义,通过一些判断,砍掉搜索树上不必要递归的子树。有时候,我们会发现某个结点对应子树的状态都不是我们要的结果,那么我们其实没必要对这个分支进行搜索,砍掉这个子树,就是剪枝。剪枝其实是和边界条件类似,边界条件本质也应该是剪枝。回顾一下之前讨论过的问题:给定n个整数,要求选出K个数,使得选出的K个数的和为sum。(我在代码中已经提供了样例,用于测试dfs速度)没剪枝的代码:#include <iostream>using原创 2022-05-20 07:31:47 · 320 阅读 · 0 评论 -
抽象形式的深度优先搜索dfs
前面我们会的dfs都是比较容易想象出搜索过程的,接下来我们看一些不那么容易想象的dfs过程,这个我们称之为抽象形式的dfs。先看一个非常简单的问题:给定n个整数,要求选出K个数,使得选出的K个数的和为sum。其实,这就是一个组合问题。我们可以依然借助深度优先搜索来解决这个问题。我们在搜索过程中,用s来表示现在当前的数值总和,k来记录选择的数的个数,deep表示当前正在枚举的数是否选择。我们可以画一个搜索树,搜索上每个结点都是一个状态,一个状态包含s和k,也就是一个状态对应当前的数值总和,一级选的原创 2022-05-17 19:41:46 · 343 阅读 · 0 评论 -
广度优先搜索中的状态表示——钥匙型迷宫问题
显然,保存状态、更新状态是广度优先搜索问题的核心,在不同类型的问题中,需要记录的信息是不相同的。本篇文章,我们将从钥匙迷宫问题、动态迷宫问题这几个例子出发,探究具体需要表示的状态,并对较多的状态进行建模。钥匙型迷宫顾名思义,钥匙型迷宫就是在普通的迷宫问题上,加入钥匙的限制,并在此基础上引申些其他概念,如钥匙能够开门。使得门所在的格子变为可通行的。如果只要拿到任意一个把钥匙即可,我们可以巧妙地用多起点bfs来解决。那么在钥匙数量更多、钥匙有多种类型地情况我们应该如何对问题建模,钥匙作为一种状态应当如何原创 2022-05-27 18:20:56 · 368 阅读 · 0 评论 -
深度优先搜索dfs和广度优先搜索bfs
文章目录深度优先搜索程序实现广度优先搜索程序实现建议理解图的基本概念和邻接矩阵再看这篇文章,我写了一篇相关的[文章]。(https://blog.youkuaiyun.com/AliceK1008/article/details/119904403?spm=1001.2014.3001.5501)深度优先搜索从某一个顶点出发开始访问,被访问的顶点做相应的标记,输出访问顶点。从被访问的顶点出发,搜索与该顶点有边的关联的某个未被访问的邻接点。再从该邻接点出发进一步搜索与该顶点有边的关联的某个未被访问的邻接点,知原创 2021-08-25 18:44:08 · 241 阅读 · 0 评论 -
深度优先搜索最优性剪枝
对于求最优解的一类问题,通常可以用可行性剪枝,比如再求解迷宫最短路的时候,如果发现当前的步数已经超过了当前的最优解,那么当前状态开始的搜索都是多余的,因为这样搜索下去永远都不可能搜到更优解。通过这样的剪枝,可以省去大量多余的计算。此外,在搜索是否有可行解的过程中,一旦找到了一组可行解,后面的搜索都不必再进行了,这算是最优性剪枝的一个特例。有一个 n×m 大小的迷宫。其中字符’S’表示起点,字符’T’表示终点,字符’*‘表示墙壁,字符’.‘表示平地。你需要从’S’出发走到’T’,每次只能向上下左右相邻的位原创 2022-05-20 07:57:29 · 639 阅读 · 0 评论 -
深度优先搜索dfs
在进行搜索时,通过控制搜索进程中的各个状态,我们能设计出一个枚举顺序,从而考虑所有可能的形式。通常,我们通过一个 dfs 函数来完成搜索枚举,而通过参数表示当前状态。例如在大部分搜索枚举问题中,可以通过 step 或 depth 表示当前枚举层数,或使用 n 表示已经选入的数量,抑或在对于一些对 和 有限制的问题中,使用 sum 表示已经选入的数量之和。让我们来看一道使用搜索枚举实现的题目:现有方程a_1 x_1 + a_2 x_2 + a_3 x_3 =0,其中2≤n≤10,1≤a[i]≤5,−2原创 2022-05-14 18:55:31 · 400 阅读 · 0 评论 -
用广度优先搜索探索迷宫问题
前面我们已经学会了如何用dfs解决迷宫最短路问题。用dfs求解迷宫有一个很大的缺点,需要枚举所有可能的路径,读入的地图一旦很大,可能的搜索方案数量会非常多,用dfs搜索显然效率非常低。我们可以借助bfs来求解迷宫问题。由于bfs时分层搜索,因此,第一次搜索到终点的时候,当前搜索的层数就是最短路径的长度。...原创 2022-05-23 19:28:14 · 553 阅读 · 0 评论 -
深度优先搜索dfs剪枝例题讲解
引爆炸弹在一个 n×m 的方格地图上,某些方格上放置着炸弹。手动引爆一个炸弹以后,炸弹会把炸弹所在的行和列上的所有炸弹引爆,被引爆的炸弹又能引爆其他炸弹,这样连锁下去。现在为了引爆地图上的所有炸弹,需要手动引爆其中一些炸弹,为了把危险程度降到最低,请算出最少手动引爆多少个炸弹可以把地图上的所有炸弹引爆。数据范围:1≤n,m≤1000;这问题其实与连通块类似。我们把可以互相引爆的炸弹放到同一个集合中,那么最后划分的集合个数就是我们要求的答案。显然,引爆集合中任意一个炸弹造成的效果都一样,我们可以遍原创 2022-05-22 08:59:44 · 431 阅读 · 0 评论 -
深度优先搜索重复性剪枝
对于某些特定的搜索方式,一个方案可能被搜索多次,这样是没有必要的。给定 n 个整数,要求选出 K 个数,使得选出来的 K 个数的和为 sum。(我直接给了一组样例)没剪枝之前的dfs代码示例:#include <iostream>using namespace std;int n, k, sum, ans;int a[40];bool xuan[40];void dfs(int s, int cnt) { for (int i = 0; i < n; i++) {原创 2022-05-20 08:08:00 · 267 阅读 · 0 评论 -
深度优先搜索——回溯
在之前的搜索没居中,我们并没有考虑选入的物品的排列顺序,但在一些题目中,会要求考虑给定数字或物品的排列,这种排列可以是在n个中符合要求的全排列,也可以是在n中找到长度为k的排列。如果使用我们之前的搜索方法,我们会发现难以用参数标记原数组中的数字选取情况,那么我们就需要一个全局的布尔数组,帮助我们标记哪些数字已经被选入了排列。另一方面,由于我们使用了这样的去安居标记数组,那么必须要用到回溯技巧,在这个分支搜索结束后,将标记数组还原若要输出 n 个数字全排列,在 dfs 数组中需要的参数需要包含已经选入的数原创 2022-05-16 15:20:44 · 512 阅读 · 0 评论 -
广度优先搜索bfs
广度优先搜索,又称宽度优先搜索,简称bfs,我们用bfs表示广度优先搜索。与深度优先搜索不同的是,广度优先搜索会先将与起始点距离较近的点搜索完毕,再搜索更远的点,二深搜却是沿着一个分支搜到最后(不撞南墙不回头)。bfs从起点开始,优先搜索离起点最近的点,然后由这个点最近的点扩展到其他稍近的点,这样一层一层扩展,就像水波扩散一样。对上图进行深度优先搜索访问的顺序的序列:A->B->E->F->C->D->G对上图进行广度优先搜索访问的顺序的序列:A->B-&g原创 2022-05-23 19:00:44 · 2207 阅读 · 0 评论 -
八皇后问题dfs及洛谷P1219拓展
N 皇后问题是一个经典的问题,在一个N×N 的棋盘上放置 N 个皇后,每行刚好放置一个并使其不能互相攻击(同一行、同一列、同一斜线上的皇后都会自动攻击)。上图就是一个合法的8黄后的解,N皇后问题是指:计算一共有多少种合法的方法放置N个皇后。很显然,我们依然会用 dfs 来求解 N 皇后问题,我们的搜索策略如下。从第 0 行开始,我们依次给每一行放置一个皇后,对于一个确定的行,我们只需要去枚举放置的列即可,在保证放置合法的情况下,一直搜索下去。下图是 N=4 时搜索树的局部形态(这个搜索树是按照逐列原创 2022-05-18 19:56:25 · 377 阅读 · 0 评论 -
广度优先搜索——动态类迷宫问题
动态类迷宫中通常会出现其中一些特殊的物品,按一定周期进行变化。我们假设迷宫中有一个楼梯,且是动态的,每隔一个单位时间,楼梯就会变换一次方向。楼梯的形状在开始时为 ‘-’ 或 ‘|’,表示其连接横向上的两个格子或纵向上的两个格子。 而当梯子转到另一方向(纵向)时,垂直于梯子方向(横向)是无法通行的。在此问题中允许蒜头君停留在某个除梯子的可行位子。动态迷宫的具体输入为第一行 n 和 m 表示迷宫的行数和列数。接下来是一个 N 行 M 列的地图,‘*‘表示障碍物,’.‘表示走廊,’|’ 或者 ‘-’ 表示一个原创 2022-05-27 22:24:52 · 540 阅读 · 0 评论 -
深度优先搜索——枚举组合
所谓枚举组合,其实就是从若干个选若干个数。比如x[1],x[2],x[3],x[4],……x[n]每个数字时0(不选)和1(选)x表示当前选到第几个书,dep表示选了几个数对于每个数来说,它有选或不选两种可能,时间复杂度就是O(2^n)核心代码:int n, k;int comb[N];void dfs(int x, int dep) { if(dep == k) { for (int i = 0; i < k; i++) { cout <原创 2022-05-16 16:10:43 · 619 阅读 · 0 评论