「学习笔记」记忆化搜索
由于我一直对搜索情有独钟,因此,如果能写记忆化搜索的绝不会写 for
循环 DP。文章部分内容来自 OI-Wiki
引入
记忆化搜索是一种通过记录已经遍历过的状态的信息,从而避免对同一状态重复遍历的搜索实现方式。因为记忆化搜索确保了每个状态只访问一次,它也是一种常见的动态规划实现方式。
我们通过下面一道题来引入。
P1434 [SHOI2002] 滑雪有一个 R×C 的二维矩阵,可以从某个点到达上下左右相邻四个点之一,当且仅当高度会减小,即这是一个下降序列。求这个下降序列长度的最大值。
我们的朴素 DFS 做法:
交上去一看,T 了一个点。
为什么 T 了呢?
我们假设 (i,j) 这个点当前被搜到,继续搜,得到最大值,返回了。
后来,又一次搜到了 (i,j) 这个点,然后又重新搜了一遍;再后来,又搜到了这个点,又重新搜了一遍......
因此,导致我们的这份代码跑得慢的原因就是多次进行同一个操作,搜索同一个变量。
为了提升速度,防止重复搜一种情况,我们设置记忆化数组来存储我们的值,同时阻止他继续重复搜索。
然后,你就可以愉快的 AC 了!
由此你也发现了,记忆化搜索相较于一般搜索速度快是因为避免了对同一状态的重复遍历。
写记忆化搜索方法
方法一
把这道题的 dp 状态和方程写出来
根据它们写出 dfs 函数
添加记忆化数组
方法二
写出这道题的暴搜程序(最好是 dfs)
将这个 dfs 改成无需外部变量的 dfs
添加记忆化数组
与递推的区别
记忆化搜索和递推,都确保了同一状态至多只被求解一次。而它们实现这一点的方式则略有不同:递推通过设置明确的访问顺序来避免重复访问,记忆化搜索虽然没有明确规定访问顺序,但通过给已经访问过的状态打标记的方式,也达到了同样的目的。
与递推相比,记忆化搜索因为不用明确规定访问顺序,在实现难度上有时低于递推,且能比较方便地处理边界情况,这是记忆化搜索的一大优势。但与此同时,记忆化搜索难以使用滚动数组等优化,且由于存在递归,运行效率会低于递推。因此应该视题目选择更适合的实现方式。
题目
P1220 关路灯
在一条路线上安装了 n 盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少)。老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。现在已知老张走的速度为 1m/s,每个路灯的位置(是一个整数,即距路线起点的距离,单位:m)、功率(W),老张关灯所用的时间很短而可以忽略不计。问:怎样最省电?n≤50
记忆化搜索代码:
版权声明: 本文为 InfoQ 作者【互联网工科生】的原创文章。
原文链接:【http://xie.infoq.cn/article/c3bcc8c93dc486023dd8e99f9】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论