搜索是ACM竞赛中的常见算法,本文的主要内容就是分析它的 特点,以及在实际问题中如何合理的选择搜索方法,提高效率。文章的第一部分首先分析了各种基本的搜索及其各自的特点。第二部分在基本搜索方法的基础上提出 一些更高级的搜索,提高搜索的效率。第三部分将搜索和动态规划结合,高效地解决实际问题,体现搜索的广泛应用性。第四部分总结全文。
文章在分析各种搜索的同时,分析了我们在解题中应该怎样合理利用它,理论结合实际,对我们的解题实践有一定的指导意义。
【 Abstract 】 Search is a algorithm which is often seen in ACM/ICPC .The main idea of this article is to analysis its specially characterist and how to choose search method reasonably for the increasing efficiency in practical problems.
The first section analysis every basic search method and each specially characterist. The second section bring up some advanced search methods to increase the efficiency.The third section is to combine the search method and dynamic programing method to solve practical problem efficiencily indicating that search methods have weed applicability.The fourth section is to sum up the article and prospect the development of search.
提起搜索,大家都不会陌生。它的应用是十分广泛的,比如目前internet上的搜索引擎,WINDOWS XP操作系统中的文件搜索。同时,搜索是编程解题的一种重要的手段,在竞赛中,我们有时会碰到一些题目,它们既不能通过建立数学模型解决,又没有现成算法 可以套用,或者非遍历所有状况才可以得出正确结果。这时,我们就必须采用搜索算法来解决问题。几乎每次ACM竞赛都要考察到这方面的内容。因此,如何更深 入地了解搜索,从而更为有效地运用这个解题的有力武器,是一个值得深入研究的问题。要掌握搜索的应用技巧,就要了解它的分类及其各方面的特点。
第一部分 基本的搜索算法
一、回溯算法
回溯算法是所有搜索算法中最为基本的一种算法,其采用了一种“走不通就掉头”思想作为其控制结构,其相当于采用了先根遍历的方法来构造解答树,可用于找解或所有解以及最优解。
评价:回溯算法对空间的消耗较少,当其与分枝定界法一起使用时,对于所求解在解答树中层较深的问题 有较好的效果。但应避免在后继节点可能与前继节点相同的问题中使用,以免产生循环。
二、深度搜索与广度搜索
深度搜索与广度搜索的控制结构和产生系统很相似,唯一的区别在于对扩展节点选取上。由于其保留了所有的前继节点,所以在产生后继节点时可以去掉一部分重复 的节点,从而提高了搜索效率。这两种算法每次都扩展一个节点的所有子节点,而不同的是,深度搜索下一次扩展的是本次扩展出来的子节点中的一个,而广度搜索 扩展的则是本次扩展的节点的兄弟节点。在具体实现上为了提高效率,所以采用了不同的数据结构.
评价:广度搜索是求解最优解的一种较好的方法,在后面将会对其进行进一步的优化。而深度搜索多用于只要求解,并且解答树中的重复节点较多并且重复较难判断时使用,但往往可以用A*或回溯算法代替。
第二部分 搜索算法的优化(一)
一、双向广度搜索
广度搜索虽然可以得到最优解,但是其空间消耗增长太快。但如果从正反两个方向进行广度搜索,理想情况下可以减少二分之一的搜索量,从而提高搜索速度。
二、分支定界
分支定界实际上是A*算法的一种雏形,其对于每个扩展出来的节点给出一个预期值,如果这个预期值不如当前已经搜索出来的结果好的话,则将这个节点(包括其子节点)从解答树中删去,从而达到加快搜索速度的目的。
三、A*算法
A*算法中更一般的引入了一个估价函数f,其定义为f=g+h。其中g为到达当前节点的耗费,而h表示对从当前节点到达目标节点的耗费的估计。其必须满足两个条件:
1. h必须小于等于实际的从当前节点到达目标节点的最小耗费h*。
2. f必须保持单调递增。
A*算法的控制结构与广度搜索的十分类似,只是每次扩展的都是当前待扩展节点中f值最小的一个,如果扩展出来的节点与已扩展的节点重复,则删去这个节点。如果与待扩展节点重复,如果这个节点的估价函数值较小,则用其代替原待扩展节点。
对A*算法的改进--分阶段A*. 当A*算法出现数据溢出时,从待扩展节点中取出若干个估价函数值较小的节点,然后放弃其余的待扩展节点,从而可以使搜索进一步的进行下去。
四、A*算法与回溯的结合(IDA*)
这是A*算法的一个变形,很好综合了A*算法的人工智能性和回溯法对空间的消耗较少的优点,在一些规模很大的搜索问题中会起意想不到的效果。它的具体名称 是 Iterative Deepening A*, 1985年由Korf提出。该算法的最初目的是为了利用深度搜索的优势解决广度A*的空间问题,其代价是会产生重复搜索。归纳一下,IDA*的基本思路 是:首先将初始状态结点的H值设为阈值maxH,然后进行深度优先搜索,搜索过程中忽略所有H值大于maxH的结点;如果没有找到解,则加大阈值 maxH,再重复上述搜索,直到找到一个解。在保证H值的计算满足A*算法的要求下,可以证明找到的这个解一定是最优解。在程序实现上,IDA* 要比 A* 方便,因为不需要保存结点,不需要判重复,也不需要根据 H值对结点排序,占用空间小。
下面,以一个具体的实例来分析比较上述几种搜索算法的效率等问题。
在scu online judge(http://cs.scu.edu.cn/acm)上有这么一道题目:这就是古老而又经典的15数码难题:在4*4的棋盘上,摆有15个棋 子,每个棋子分别标有1-15的某一个数字。棋盘中有一个空格,空格周围的棋子可以移到空格中。现给出初始状态和目标状态,要求找到一种移动步骤最少的方 法。
看到这个题目,会发觉几乎每个搜索算法都可以解这个问题。而事实确实如此。
首先考虑深度优先搜索,它会遍历这棵解答树。这棵解答树最多可达16!个节点,深度优先搜索必须全部遍历后,才能从所有解中选出最小的一个做为答案,其代价是非常巨大的。
其次考虑广度深度优先搜索,这不失为一个好办法。因为广度优先搜索的层次遍历解答树的特点,一旦搜索到一个目标节点,那么这时的深度一定是最优解,而不必 象深度优先搜索那样继续搜索目标节点,最后比较才能得出最优解。该搜索方法在这道题目上会遇见致命的问题:广度深度优先搜索是一种盲目的搜索,深度比较大 的测试数据会产生大量的无用的节点,同时消耗很多时间在重复节点的判断上。
为了减少重复的节点,加入人工智能性,马上可以想到用A*算法。经过分析发现,该方法对避免产生大量的无用的节点起到了一定的效果,但是会花97%以上的 时间去判断新产生节点是否与已扩展的和待扩展的节点重复。看来如何提高判重的速度成为该题目的关键。解决这个问题有很多办法,比如引入哈希表,对已扩展的 和待扩展的节点采用哈希表存储,减少判重的代价,或者对已扩展的和待扩展的节点采用桶排序,也可以减少判重的代价。我们现在来尝试一下用 IDA*算法。该算法有个值得注意的地方:对估计函数的选取。如果选用当前状态每个位置上与目标状态每个位置上相同节点的数目加当前状态的深度作为估计函 数,由于当前状态每个位置上与目标状态每个位置上相同节点的数目这个值一般较小,不能明显显示各个状态之间的差别,运行过程中会产生大量的无用的节点,同 样会使效率很低,不能在60s以内完成计算。比较优化的一个办法是选用由于当前状态每个位置上的数字偏离目标节点该数字的位置的距离加当前状态的深度作为 估计函数。这个估计函数的选取没有统一的标准,找到合适的该函数并不容易,但是可以大致按照这个原则:在一定范围内加大各个状态启发函数值的差别。
实践证明,该方法用广泛的通用性,在很多情况下可以替换一般的深度优先搜索和广度优先搜索。
第三部分 搜索算法的优化(二)
该部分将谈到搜索与其他算法的结合。再看scu online judge的一道题目: 给定一个8 * 8的国际象棋棋盘。给出棋盘上任意两个位置的坐标,问马最少几步可以从一个位置跳到另外一个位置。
该题目同样是求最优解,如果用一般的深度优先搜索是很容易超时的。如果用广度优先搜索,会消耗大量的内存,而且效率是很低的。这里,我们将尝试用深度优先搜索加动态规划的算法解决该问题。
将该棋盘做为存储状态的矩阵。每个矩阵元素的值是该位置到初始位置最少需要的步数。初始位置的元素值为0。其他位置的元素初始化为一个很大的正整数。首先 从初始位置开始深度优先搜索,例如某次从(i1,j1)到达位置(i2,j2),如果(i2,j2)处的值大于(i1,j1)的值加1,则(i2,j2) 处的值更新为(i1,j1)+ 1,表示从(i1,j1) 跳到(i2,j2)比从其他地方跳到(i2,j2)更优,不断的进行这个过程,直到不能进行下去位置,那么最后的目标位置的值就是解。这就是一个动态规划 的思想,每个位置的最优解都是由其他能够一次跳到这个位置的位置的值决定的,而且是它们中的最小值。同时,该动态规划又借助深度优先搜索这个工具,完成对 每个位置的值的刷新,可以算是一个比较经典的深度优先搜索和动态规划的结合。该问题还需要注意一个剪枝的问题,从起始位置到目标位置的最大步数是多少?经 过计算,最大值是6。所以一旦某个位置的值是6了,就不必再将它去刷新另外的位置,从而剪去了对很多不必要子树的搜索,大大提高了效率。
第四部分结语
本文的主要的篇幅讲的都是理论,但是根本的目的还是指导实践。搜索,据我认为,是当今ACM竞赛中最常规、也最能体现解题者水平的一类解题方法。 “纸上得来终觉浅,绝知此事要躬行。”要想真正领悟、理解各种搜索的思想,掌握搜索的解题技巧,还需要在实践中不断地挖掘、探索。实践得多了,也就能体会 到渐入佳境之妙了。算法的优化是无穷尽的。
【转】ACM搜索算法总结 --By GreenHand的更多相关文章
-
[转载]ACM搜索算法总结(总结)
原文地址:ACM搜索算法总结(总结)作者:GreenHand 搜索是ACM竞赛中的常见算法,本文的主要内容就是分析它的 特点,以及在实际问题中如何合理的选择搜索方法,提高效率.文章的第一部分首先分析了 ...
-
[ACM训练] 算法初级 之 搜索算法 之 广度优先算法BFS (POJ 3278+1426+3126+3087+3414)
BFS算法与树的层次遍历很像,具有明显的层次性,一般都是使用队列来实现的!!! 常用步骤: 1.设置访问标记int visited[N],要覆盖所有的可能访问数据个数,这里设置成int而不是bool, ...
-
ACM二分搜索算法
二分搜索算法就是把要搜索的数据在搜索文本中根据情况进行折半,比如要在2 6 4 9 3 8 7 3 5中找到找到4的位置,那么可以考虑先把数据进行排序,然后把拍好后的数据的中间的那个数据和要查找的数据 ...
-
ACM 广度优化搜索算法总结
广度优化搜索算法的本质:要求每个状态不能重复,这就需要我们:第一次先走一步可以到达的状态,如果还没有找到答案,就需要我们走到两步可以到达的状态.依次下去 核心算法:队列 基本步骤: ...
-
ACM 深度优化搜索算法小总结
深度优化搜索算法的本质:就是从一状态不断转移,如果无法转移了就需要返回上一个状态,知道找到解为止. 其核心:递归函数 基本模型: dfs(int i, int j) { //控制结束条件 //进行状态 ...
-
[ACM训练] 算法初级 之 搜索算法 之 深度优先算法DFS (POJ 2251+2488+3083+3009+1321)
对于深度优先算法,第一个直观的想法是只要是要求输出最短情况的详细步骤的题目基本上都要使用深度优先来解决.比较常见的题目类型比如寻路等,可以结合相关的经典算法进行分析. 常用步骤: 第一道题目:Dung ...
-
ACM/ICPC 之 数论-费马大定理(HNUOJ 13371)
好歹我是数学专业的学生,还是要写写训练的时候遇到的数学问题滴~~ 在ACM集训的时候在各高校OJ上也遇见过挺多的数学问题,例如大数的处理,素数的各种算法,几何问题,函数问题(单调,周期等性质),甚至是 ...
-
acm算法模板(5)
STL 中 sort 函数用法简介 做 ACM 题的时候,排序是一种经常要用到的操作.如果每次都自己写个冒泡之类的 O(n^2) 排序,不但程序容易超时,而且浪费宝贵的比赛时间,还很有可能写错. ST ...
-
ACM比赛技巧
一.语言是最重要的基本功 无论侧重于什么方面,只要是通过计算机程序去最终实现的竞赛,语言都是大家要过的第一道关.亚洲赛区的比赛支持的语言包括C/C++与JAVA.笔者首先说说JAVA,众所周知,作 ...
随机推荐
-
MySQL表结构及数据的备份
1.Navicat for MySQL 选择要保存的表,右键转储SQL文件,导出的sql文件中包括表的定义和表的数据两部分. 其他办法: (1) create table dust select * ...
-
[开源框架推荐]Icepdf:纯java的pdf文档的提取和转换库
ICEpdf 是一个轻量级的开源 Java 语言的 PDF 类库.通过 ICEpdf 可以用来浏览.内容提取和转换 PDF 文档,而无须一些本地PDF库的支持. 可以用来做什么? 1.从pdf文件中提 ...
-
CSS3 animation的steps方式过渡
animation默认以ease方式过渡,它会在每个关键帧之间插入补间动画,所以动画效果 是连贯性的.除了ease,linear.cubic-bezier之类的过渡函数都会为其插入补间. 但有些效果不 ...
-
解决Fetching android sdk component information加载过久问题
安装完成后,如果直接启动,Android Studio会去获取 android sdk 组件信息,这个过程相当慢,还经常加载失败,导致Android Studio启动不起开.解决办法就是不去获取and ...
-
Cisco 绑定mac地址
在Cisco中有以下三种方案可供选择,方案1和方案2实现的功能是一样的,即在具体的交换机端口上绑定特定的主机的MAC地址(网卡硬件地址),方案3是在具体的交换机端口上同时绑定特定的主机的MAC地址(网 ...
-
Dom 简介
HTML DOM 简介 DOM 教程 DOM 节点 HTML DOM 定义了访问和操作 HTML 文档的标准. 您应该具备的基础知识 在您继续学习之前,您需要对以下内容拥有基本的了解: HTML CS ...
-
codeforces 630C - Lucky Numbers 递推思路
630C - Lucky Numbers 题目大意: 给定数字位数,且这个数字只能由7和8组成,问有多少种组合的可能性 思路: 假设为1位,只有7和8:两位的时候,除了77,78,87,88之外还哇哦 ...
-
linux之关于学习必备知识
文件列表的定义: 第一个字符表示文件类型 d为目录 -为普通 1为链接 b为可存储的设备接口 c为键盘鼠标等输入设备 2~4个字符表示所有者权限,5~7个字符表示所有者同组用户权限,8~10 ...
-
20155204 2016-2017-2 《Java程序设计》第4周学习总结
20155204 2016-2017-2 <Java程序设计>第4周学习总结 教材学习内容总结 继承是类与类之间的联系,接口是方法与类之间的联系,多态就是指利用接口和继承来派生许多类. 有 ...
-
java实现心型、99乘法demo
package com.js.ai.modules.pointwall.interfac; import java.awt.Font; import javax.print.attribute.sta ...