DFS(深度优先搜索) 总是需要重置 visited 的状态吗?
问题来自 P1902 刺杀大使,在最初的实现中 DFS 中一段代码如下:
visited[x2][y2] = true;
flag = dfs(v, x2, y2);
visited[x2][y2] = false;
if (flag) { break; }
从格点([x2][y2]
) 出发进行搜索,搜索开始前,会设置 visited[x2][y2] = true
;搜索结束后,会重新设置 visited[x2][y2] = false
。在没有解的情况下,算法会搜索二维数组中所有可能的路径(四个方向),这个路径被称为自回避行走(SAW, Self-Avoiding Walks)。目前还没对任意尺寸二维数组的 SAW 路径的通项公式,但是可以知道 SAW 路径个数和二维数组的尺寸是非线性关系。所以在没有解的情况下,使用上面的算法会导致 TLE(搜索的路径数远远多于数组的元素个数)。
为了解决超时问题,我们可以在搜索结束后,不再重置 visited[x2][y2]
,也就是说在整个搜索过程中,对于任意的一个格点(lattice),我们至多访问一次。此时,算法的最坏复杂度为 O(n*m)
。
证明
关于该算法正确性的一个简短证明:
命题:对于搜索失败的格点(即,从该格点出发),无需再次访问,即使再次访问搜索结果也不会发生变化。
我们使用反证法来证明。对于搜索失败的格点 A
,可能会存在一条成功的路径。那么之前对格点 A
的搜索会失败,是因为这条成功路径上的某个格点 B
已经被访问过,导致这条路径不通。
如果这条成功路径上的这个格点 B
之前已经被访问过,但是算法没有中止,就代表从格点 B
出发的路径也存在某个格点 C
已经被访问过。重复这个步骤,我们可以得到,终点 D
也应该之前被访问过,这当然是矛盾的。
从而我们可知,若从某一格点出发搜索失败,则表示并不存在从该格点出发的成功路径,不然程序早就在访问这个格点之前就已经中止了。
奇怪的代码
在查看题目题解的时候,我看到这样的一段代码,
vis[x][y] = 1;
dfs(x, y);
vis[x][y] = 0;
照例说这个重置 vis
状态的解法,会导致超时问题。但是我提交后发现,这个解法并未超时。这让我思考了很久,明明是和我相同的写法,为什么上面的代码不会超时呢?直到我看到代码作者把变量 x
和 y
定义在了函数外,我才明白了原因——搜索开始前的 x
, y
和搜索结束后的 x
, y
的值并不相同,在递归的过程中,x
,y
作为全局变量并没有暂存下来,所以最后重置的 vis[x][y]
和搜索前的不是同一个。这也就是我们看到这个代码歪打正着地 AC 的原因了。
参考资料
DFS(深度优先搜索) 总是需要重置 visited 的状态吗?的更多相关文章
- 回溯算法 DFS深度优先搜索 (递归与非递归实现)
回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...
- HDU 1241 Oil Deposits DFS(深度优先搜索) 和 BFS(广度优先搜索)
Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...
- HDU 4707 Pet(DFS(深度优先搜索)+BFS(广度优先搜索))
Pet Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissio ...
- 『ACM C++』HDU杭电OJ | 1416 - Gizilch (DFS - 深度优先搜索入门)
从周三课开始总算轻松了点,下午能在宿舍研究点题目啥的打一打,还好,刚开学的课程还算跟得上,刚开学的这些课程也是复习以前学过的知识,下半学期也不敢太划水了,被各种人寄予厚望之后瑟瑟发抖,只能努力前行了~ ...
- 步步为营(十五)搜索(一)DFS 深度优先搜索
前方大坑预警! 先讲讲什么是搜索吧. 有一天你去一个果园摘梨子,果农告诉你.有一棵树上有一个金子做的梨子,找到就是你的,你该怎么找? 地图例如以下: S 0 0 0 0 0 0 0 0 0 0 0 0 ...
- [算法总结]DFS(深度优先搜索)
目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...
- 浅谈dfs深度优先搜索
深度优先搜索(Depth First Search)是一种常见的暴力算法 此算法上限和下限较高,容易上手,适用情形多,学习性价比高 下限高于有固定的模板,且时间复杂度明显优于暴力枚举,容易拿到题目部分 ...
- 回溯 DFS 深度优先搜索[待更新]
首先申明,本文根据微博博友 @JC向北 微博日志 整理得到,本文在这转载已经受作者授权! 1.概念 回溯算法 就是 如果这个节点不满足条件 (比如说已经被访问过了),就回到上一个节点尝试别 ...
- DFS(深度优先搜索)
简介 DFS的过程是一个递归过程,它是从图中的某个顶点开始,首先访问起始点v,然后选择一个与顶点v相邻的且没有被访问的顶点w,以w为起始顶点,在进行DFS,直到图中所有与v相邻的顶点都被访问过为止. ...
- DFS——深度优先搜索的一般格式
DFS是一种深度优先的搜索思想,运用递归完成搜索,本质上也算是穷举思想的一类,可以通过剪枝进行优化. DFS的核心是回溯和递归, 如果以迷宫为例,一般会指定走各个方向的顺序(例如先左再上再右再下).从 ...
随机推荐
- 自定义组件中使用half-screen-dailog 无法舒勇外部样式
为了将弹窗更方便的调用,封装了组件,但是发现一个问题, 外部样式类在组件中是无法正常使用的. 也就说在组件的wxss中是无法正常使用.weui-half-screen-dialog 这个外部样式类,然 ...
- WIn环境基于vs编辑器,Qt应用申请管理员权限的解决方法(转载)
原文章地址:https://blog.csdn.net/weixin_38416696/article/details/103879377 基本按照那个文章的操作.基本可以了. 唯一问题就是那个vs的 ...
- windows server 2008 创建计划任务不能正常执行
- 在MDK 5中打开MDK 4工程要注意的问题1
我是生手,对于MDK的理解还很简单.以下内容是遇到的一种情况. 有一个MDK 4工程,要求顺序点亮4个LED灯,工程已经建好. 在MDK 5中打开,编译都没问题,要烧写时,提示"can no ...
- 在Vim编辑器中查找选定文本
按照任意选定文本查找: 1. 进入visiual模式选定文本, 按 y 键复制: 2. 按 / 键进入查找模式: 3. 按 Ctrl + r 打开vim寄存器: 4. 按 " 键将寄存器内容 ...
- 多线程中使用COM 的注意事项
最近做了一个TCP Server的程序,其中需用使用COM组件,但是tcp 的部分是阻塞的,所以开了一个线程用来专门接收来自客户端的信号,当接收到信号后,再根据情况处理. 按照这个思路,在程序的一开始 ...
- K8S 性能优化 - 大型集群 CIDR 配置
前言 K8S 性能优化系列文章,本文为第三篇:Kubernetes 大型集群 CIDR 配置最佳实践. 系列文章: <K8S 性能优化 - OS sysctl 调优> <K8S 性能 ...
- C#多线程开发-处理异步操作中的异常
C#多线程开发-处理子线程中的异常 在平时的多线程开发中,对于异常的处理是至关重要的,千万不能马虎.如果在实际的项目中,对于某些线程中的异常没有处理,会直接导致整个程序崩溃,软件无法使用. 其中需要说 ...
- Prometheus服务发现之kubernetes_sd_config
一.为什么要使用Prometheus服务发现 之前我们讲过通过配置prometheus-operator的CRD ServiceMonitor来达到K8S集群相关组件和微服务的监控的目的,可以在Ser ...
- window身上的方法 弹出框/打开和关闭
window身上的方法内置函数 alert() parseInt() parseFloat() setInterval(); setTimeout(); clearTimeout(); clearIn ...