• 【转】搜索算法的剪枝优化


    搜索算法按搜索的方式分有两类,一类是深度优先搜索,一类是广度优先搜索。我们知道,深度搜索编程简单,程序简洁易懂,空间需求也比较低,但是这种方法的 时间复杂度往往是指数级的,倘若不加优化,其时间效率简直无法忍受;而广度优先搜索虽然时间复杂度比前者低一些,但其庞大的空间需求量又往往让人望而却步。 所以,对程序进行优化,就成为搜索算法编程中最关键的一环。本文所要讨论的便是搜索算法中优化程序的一种基本方法叫“剪枝”。 一、what is it?       搜索的进程可以看作是从树根出发,遍历一棵倒置的树——搜索树的过程。而所谓剪枝,顾名思义,就是通过某种判断,避免一些不必要的遍历过程,形象的说,就是剪去了搜索树中的某些“枝条”,故称剪枝。应用剪枝优化的核心问题是设计剪枝判断方法,即确定哪些枝条应当舍弃,哪些枝条应当保留的方法。 二、剪枝的原则 原则之一:正确性。    因为它能够“剪去”搜索树中的一些“枝条”。然而,如果在剪枝的时候,将“长有”我们所需要的解的枝条也剪掉了,那么,一切优化也就都失去了意义。所以,对剪枝的第一个要求就是正确性,即必须保证不丢失正确的结果,这是剪枝优化的前提。我们利用“必要条件”来进行剪枝判断。也就是说,通过解所必须具备的特征、必须满足的条件等方面来考察待判断的枝条能否被剪枝。这样,就可以保证所剪掉的枝条一定不是正解所在的枝条。 原则之二:准确性。 即能够尽可能多的剪去不能通向正解的枝条。准确性可以说是剪枝优化的生命。 原则之三:高效性。 经常还需要提高判断操作本身的时间效率。 综上所述,我们可以把剪枝优化的主要原则归结为六个字:正确、准确、高效。 我们可以把常用的剪枝判断大致分成以下两类: 可行性剪枝。 最优性剪枝(上下界剪枝)。 三、可行性剪枝 搜索过程可以看作是对一棵树的遍历。在很多情况下,并不是搜索树中的所有枝条都能通向我们需要的结果,很多的枝条实际上只是一些死胡同。如果我们能够在刚刚进入这样的死胡同的时候,就能够判断出来并立即剪枝,程序的效率往往会得到提高。而所谓可行性剪枝,正是基于这样一种考虑。 下面我们举一个例子——Betsy的旅行(USACO)。 题目简述:一个正方形的小镇被分成N的平方个小方格,Betsy要从左上角的方格到达左下角的方格,并且经过每个方格恰好一次。编程对于给定的N,计算出Betsy能采用的所有的旅行路线的数目。 我们用深度优先的回溯方法来解决这个问题:Betsy从左上角出发,每一步可以从一个格子移动到相邻的没有到过的格子中,遇到死胡同则回溯,当移动了N2-1步并达到左下角时,即得到了一条新的路径,继续回溯搜索,直至遍历完所有道路。 但是,仅仅依照上述算法框架编程,时间效率极低,对N=6的情况无法很好的解决,所以,优化势在必行。对本题优化的关键就在于当搜索到某一个步骤时,能够提前判断出在后面的搜索过程中是否一定会遇到死胡同,而可行性剪枝正可以在这里派上用场。 我们首先从“必要条件”,即合法的解所应当具备的特征的角度分析剪枝的方法,主要有两个方向:对于一条合法的路径,除出发点和目标格子外,每一个中间格子都必然有“一进一出”的过程。所以在搜索过程中,必须保证每个尚未经过的可格子都与至少两个尚未经过的格子相邻(除非当时Betsy就在它旁边)。这里,我们是从微观的角度分析问题。 在第一个条件的基础上,我们还可以从宏观的角度分析,进一步提高剪枝判断的准确性。显然,在一个合法的移动方案的任何时刻,都不可能有孤立的区域存在。虽然孤立区域中的每一个格子也可能都有至少两个相邻的空的格子,但它们作为一个整体,Betsy已经不能达到。我们也应当及时判断出这种情况,并避免之。 以上两个剪枝判断条件都是正确的,其准确度也比较高。但是,仅仅满足这两点还不够,剪枝判断的操作过程还必须力求高效。假如我们在每次剪枝判断时,都简单的对N2个格子进行一遍扫描,其效率的低下可想而知。因此,我们必须尽可能的简化判断的过程。 实际上,由于Betsy的每一次移动,只会影响到附近的格子,所以每次执行剪枝判断时,应当只对她附近的格子进行检查:对于第一个剪枝条件,我们可以设一个整型标志数组,分别保存与每个格子相邻的没被经过的格子的数目,Betsy每次移动到一个新位置,都只会使与之相邻的至多4个格子的标志值发生变化,只要检查它们的标志值即可。而对于第二个剪枝条件,处理就稍稍麻烦一些。但我们仍然可以使用局部分析的方法,即只通过对Betsy附近的格子进行判断,就确定是否应当剪枝,下图简要说明了剪枝的原理: 1、搜索算法的剪枝优化 - 墨涵 - 墨涵天地

    上图给出了可以剪枝的三种情况。由于Betsy到过的所有格子都一定是四连通的,所以每种情况下的两个白色的格子之间必定是不连通的,它们当中必然至少有一个是属于某个孤立区域的,都一定可以剪枝。 经过上述的优化,程序的时间效率有了很大的提高        在应用可行性剪枝的时候,首先要多角度全面分析问题的特点(本题就是从微观和宏观两个角度设计剪枝方法),找到尽可能多的可以剪枝的情况;同时,还必须注意提高剪枝的时间效率,所以我们使用了“局部判断”的方法,特别是在处理第二个剪枝条件时,更是通过局部判断来体现整体性质(是否有孤立区域),这一技巧不仅在设计剪枝方法的时候能够发挥作用,在其他方面也有着极为广泛的应用。 四 、最优性剪枝        在我们平时遇到的问题中,有一大类是所谓最优化问题,即所要求的结果是最优解。如果我们使用搜索方法来解决这类问题,那么,最优性剪枝是一定要考虑到的。       首先要作一些说明:我们知道,解的优劣一般是通过一个评价函数来评判的。这里定义一个抽象的评价函数——“优度”,它的值越大,对应的解也就越优(对于具体的问题,我们可以认为“优度”代表正的收益或负的代价等)。 然后,我们再来回顾一下搜索最优解的过程:一般情况下,我们需要保存一个“当前最优解”,实际上就是保存解的优度的一个下界。在遍历到搜索树的叶子节点的时候,我们就能得到一个新的解,当然也就得到了它的评价函数值,与保存的优度的下界作比较,如果新解的优度值更大,则这个优度值就成为新的下界。搜索结束后,所保存的解就是最优解。 那么,最优性剪枝又是如何进行的呢?当我们处在搜索树的枝条上时,可以通过某种方法估算出该枝条上的所有解的评价函数的上界,即所谓估价函数。显然,大于当前保存的优度的下界,是该枝条上存在最优解的必要条件,否则就一定可以剪枝。所以,最优性剪枝也可以称为“上下界剪枝”。同时,我们也可以看到,最优性剪枝的核心问题就是估价函数的建立。

  • 相关阅读:
    Java实习二
    Java实习一
    从0开始 Java实习 黑白棋
    从0开始 Java学习 packet用法
    解题报告:hdu 1276 士兵队列训练问题
    从0开始 数据结构 AC自动机 模板(from kkke)
    从0开始 数据结构 AC自动机 hdu 2222
    从0开始 数据结构 字典树 hdu1251
    从0开始 图论学习 拓扑排序 链式前向星表示法
    ui爬虫工具-未完成
  • 原文地址:https://www.cnblogs.com/lzhitian/p/2485434.html
Copyright © 2020-2023  润新知