问题来自 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 状态的解法,会导致超时问题。但是我提交后发现,这个解法并未超时。这让我思考了很久,明明是和我相同的写法,为什么上面的代码不会超时呢?直到我看到代码作者把变量 xy 定义在了函数外,我才明白了原因——搜索开始前的 x, y 和搜索结束后的 x, y 的值并不相同,在递归的过程中,xy 作为全局变量并没有暂存下来,所以最后重置的 vis[x][y] 和搜索前的不是同一个。这也就是我们看到这个代码歪打正着地 AC 的原因了。

参考资料

DFS(深度优先搜索) 总是需要重置 visited 的状态吗?的更多相关文章

  1. 回溯算法 DFS深度优先搜索 (递归与非递归实现)

    回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...

  2. HDU 1241 Oil Deposits DFS(深度优先搜索) 和 BFS(广度优先搜索)

    Oil Deposits Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total ...

  3. HDU 4707 Pet(DFS(深度优先搜索)+BFS(广度优先搜索))

    Pet Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissio ...

  4. 『ACM C++』HDU杭电OJ | 1416 - Gizilch (DFS - 深度优先搜索入门)

    从周三课开始总算轻松了点,下午能在宿舍研究点题目啥的打一打,还好,刚开学的课程还算跟得上,刚开学的这些课程也是复习以前学过的知识,下半学期也不敢太划水了,被各种人寄予厚望之后瑟瑟发抖,只能努力前行了~ ...

  5. 步步为营(十五)搜索(一)DFS 深度优先搜索

    前方大坑预警! 先讲讲什么是搜索吧. 有一天你去一个果园摘梨子,果农告诉你.有一棵树上有一个金子做的梨子,找到就是你的,你该怎么找? 地图例如以下: S 0 0 0 0 0 0 0 0 0 0 0 0 ...

  6. [算法总结]DFS(深度优先搜索)

    目录 一.关于DFS 1. 什么是DFS 2. DFS的搜索方式 二.DFS的具体实现 三.剪枝 1. 顺序性剪枝 2. 重复性剪枝 3. 可行性剪枝 4. 最优性剪枝 5. 记忆化剪枝 四.练习 一 ...

  7. 浅谈dfs深度优先搜索

    深度优先搜索(Depth First Search)是一种常见的暴力算法 此算法上限和下限较高,容易上手,适用情形多,学习性价比高 下限高于有固定的模板,且时间复杂度明显优于暴力枚举,容易拿到题目部分 ...

  8. 回溯 DFS 深度优先搜索[待更新]

      首先申明,本文根据微博博友 @JC向北 微博日志 整理得到,本文在这转载已经受作者授权!   1.概念   回溯算法 就是 如果这个节点不满足条件 (比如说已经被访问过了),就回到上一个节点尝试别 ...

  9. DFS(深度优先搜索)

    简介 DFS的过程是一个递归过程,它是从图中的某个顶点开始,首先访问起始点v,然后选择一个与顶点v相邻的且没有被访问的顶点w,以w为起始顶点,在进行DFS,直到图中所有与v相邻的顶点都被访问过为止. ...

  10. DFS——深度优先搜索的一般格式

    DFS是一种深度优先的搜索思想,运用递归完成搜索,本质上也算是穷举思想的一类,可以通过剪枝进行优化. DFS的核心是回溯和递归, 如果以迷宫为例,一般会指定走各个方向的顺序(例如先左再上再右再下).从 ...

随机推荐

  1. 微信小程序按下去的样式

    微信小程序设置 hover-class,实现点击态效果 目前支持 hover-class 属性的组件有三个:view.button.navigator. 不支持 hover-class 属性的组件,同 ...

  2. CH573 CH582 CH579蓝牙主机(Central)例程讲解一(主机工作流程)

    蓝牙主机,顾名思义,就是一个蓝牙主设备,与从机建立连接进行通信,可以接收从机通知,也可以给从机发送信息,可将Central例程和Peripheral例程结合使用. 蓝牙主机例程的工作流程大致如下: 一 ...

  3. A better jump —— 优化游戏中的跳跃

    之前一提起角色的跳跃,想当然的想法就是:给角色一个向上的初速,然后由Unity的物理系统接管就好了嘛,这样忽略空气摩擦的影响,根据重力加速度,角色向上跳到最高点的时间和由最高点落下的时间相等,不是很合 ...

  4. 关于Windows10纯净启动的相关修改流程

    关于纯净启动的相关流程 自动登录 打开命令提示符运行control userpasswords2后回车 在弹出的用户账户窗口中,取消勾选"要使用本计算机,用户必须输入用户名和密码" ...

  5. 自动化兼容性测试工具——WeTest

    这个作业属于哪个课程 2021春软件工程实践|W班(福州大学) 这个作业要求在哪里 软件工程实践总结&个人技术博客 这个作业的目标 分享自动化兼容性测试工具的使用 其他参考文献 ... 目录 ...

  6. Java-01enum常量特定方法

    OnJava8-Enum-常量特定方法 用枚举实现责任链模式 责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条"链& ...

  7. 帮你积累音视频知识,Agora 开发者漫游指南正式启航

    "运气是设计的残留物."--John Milton 如果玩过<全面战争:中世纪 II>,或者读过 John Milton 书的人,可能对这句话有印象.我们发现,很多小伙 ...

  8. 《golong入门教程📚》,从零开始入门❤️(建议收藏⭐️)

    Go语言学习笔记 本菜鸟的Go语言学习笔记,历时1个月,包含了Go语言大部分的基本语法(不敢说全部),学习期间参考了各种视频,阅读了各种文章,主要参考名单如下: 点击跳转到参考名单<( ̄︶ ̄)& ...

  9. springboot---多环境启动命令格式

    一.多环境命令启动 maven插件中首先clean,再package打包,(修改字符集为UTF-8) 使用cmd命令java -jar s(Tab键自动补全)  -spring.profiles.ac ...

  10. 记一次 .NET 某企业 ERP网站系统 崩溃分析

    一:背景 1. 讲故事 前段时间收到了一个朋友的求助,说他的ERP网站系统会出现偶发性崩溃,找了好久也没找到是什么原因,让我帮忙看下,其实崩溃好说,用 procdump 自动抓一个就好,拿到 dump ...