五大常用算法之

文章目录

  • 基本思想

  • 一般步骤

  • 检测

  • 子集树模板

    • 子集树模板递归版

    • 子集树模板迭代版

  • 排列树模板

    • 排列树模板递归版

    • 排列树模板迭代版

  • 应用举例

    • 应用子集树模板思想

    • 应用排列树模板思想

回溯法最优解排列组合解空间搜索中存在典型应用。

我们知道动态规划贪婪算法都要求无后效性,即子问题的解是当前的最优解,不能回退。当这种要求得不到满足时,一种的通常做法是采用回溯的方法进行求解。

回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。

回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。

基本思想

在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。

若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束

一般步骤

  1. 定义一个解空间(子集树排列树二选一) 理解 重要

  2. 利用适于搜索的方法组织解空间。

  3. 利用深度优先法搜索解空间。

  4. 利用剪枝函数避免移动到不可能产生解的子空间。

检测

检测是判断是否剪枝的依据

  1. 约束函数-是否满足显约束(存在)

  2. 限界函数-是否满足隐约束(最优)

子集树模板

遍历子集树(完全二叉树),时间复杂度 O(2^n),可以分为两类题型:

  1. 如果解的长度是不固定的,那么解和元素顺序无关,即可以从中选择0个多个。例如:子集,迷宫,…

  2. 如果解的长度是固定的,那么解和元素顺序有关,即每个元素有一个对应的状态。例如:子集,8皇后,…

解空间的个数指数级别的,为2^n,可以用子集树来表示所有的解

适用于幂集子集0-1背包装载8皇后迷宫、…

子集树模板递归版

'''求集合{1, 2, 3, 4}的所有子集'''class SubSetTree:    def __init__(self, a):        self.a = a      # 数据列表        self.n = len(a) # 数据长度        self.x = []     # 一个解        self.X = []     # 一组解    def conflict(self, k):    # 冲突检测:无        return False    # # 例子,冲突检测:奇偶性相同,且和小于8的子集    # def conflict(self, k):    #     # 根据部分解,构造部分集    #     if len(self.x)==0:    #         return False    #     if 0 < sum(map(lambda y:y%2, self.x)) < len(self.x) or sum(self.x) >= 8: # 只比较 x[k] 与 x[k-1] 奇偶是否相间    #         return True        #     return False # 无冲突    # 子集树递归模板    def backtrack(self, k): # 到达第k个元素        if k >= self.n:  # 超出最尾的元素            self.X.append(self.x[:]) # 保存(一个解)        else:            for i in [1, 0]: # 遍历元素 a[k] 的两种选择状态:1-选择,0-不选                if i==1:                    self.x.append(self.a[k])                if not self.conflict(k): # 剪枝                    self.backtrack(k+1)                if i==1:                    self.x.pop()              # 回溯    def SovleSubSet(self):        self.backtrack(0)        return self.Xif __name__ == '__main__':    test = SubSetTree([1, 2, 3, 4])    res = test.SovleSubSet()    print(res)   # [[1, 2, 3, 4], [1, 2, 3], [1, 2, 4], [1, 2], [1, 3, 4], [1, 3], [1, 4], [1], [2, 3, 4], [2, 3], [2, 4], [2], [3, 4], [3], [4], []]

子集树模板迭代版

排列树模板

遍历排列树,时间复杂度O(n!)

解空间是由 n 个元素的排列形成,也就是说 n 个元素的每一个排列都是解空间中的一个元素,那么,最后解空间的组织形式是排列树

适用于:n个元素全排列旅行商、…

排列树模板递归版

'''求[1,2,3,4]的全排列'''class PermTree:    def __init__(self, data):        self.n = len(data)        self.x = data # 一个解        self.X = []   # # 一组解          # # 冲突检测:无    # def conflict(self, k):    #     return False # 无冲突    # 例子,冲突检测:元素奇偶相间的排列    def conflict(self, k):        if k==0:                   # 第一个元素,肯定无冲突            return False                    if self.x[k-1] % 2 == self.x[k] % 2: # 只比较 x[k] 与 x[k-1] 奇偶是否相同            return True                    return False # 无冲突        # 排列树递归模板    def backtrack(self, k): # 到达第k个位置         if k >= self.n:  # 超出最尾的位置            self.X.append(self.x[:]) # 注意x[:]        else:            for i in range(k, self.n): # 遍历后面第 k~n-1 的位置                self.x[k], self.x[i] = self.x[i], self.x[k]                if not self.conflict(k):    # 剪枝                    self.backtrack(k+1)                self.x[i], self.x[k] = self.x[k], self.x[i] # 回溯    def SovlePerm(self):        self.backtrack(0)        return self.X            # 测试if __name__ == '__main__':    test = PermTree([1,2,3,4])    res = test.SovlePerm()    print(res)   # [[1, 2, 3, 4], [1, 4, 3, 2], [2, 1, 4, 3], [2, 3, 4, 1], [3, 2, 1, 4], [3, 4, 1, 2], [4, 3, 2, 1], [4, 1, 2, 3]]
(0)

相关推荐

  • (1条消息) 又一个同学被快手挂掉了

    今天是小浩算法 "365刷题计划" 第105天.这是昨天一个同学面试快手被问到的算法题,很不幸的是他被挂掉了.征得对方同意后,拿出来分享给大家~ (如果要进入算法交流群的, 关注后 ...

  • Java五大常用算法

    算法一:分治法 基本概念 1.把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并. 2.分治策略是对于一个 ...

  • 「五大常用算法」一文搞懂分治算法

    首发公众号:bigsai 前言 分治算法(divide and conquer)是五大常用算法(分治算法.动态规划算法.贪心算法.回溯法.分治界限法)之一,很多人在平时学习中可能只是知道分治算法,但是 ...

  • 五大基本算法之动态规划算法 DP dynamic programming | Echo Blog

    dynamic programming 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法. 20世纪50年代初美 ...

  • Python数据挖掘常用的工具有哪些?五大常用库!

    Python是一种非常特殊的编程语言,可应用于不同场景,比如说数据挖掘.运维.爬虫.开发Python都可以广泛的应用.和其他语言对比,Python语法清晰.入门简单.具有丰富的第三方库,因此在数据挖掘 ...

  • 17个机器学习的常用算法!

    编辑:图灵人工智能 根据数据类型的不同,对一个问题的建模有不同的方式.在机器学习或者人工智能领域,人们首先会考虑算法的学习方式.在机器学习领域,有几种主要的学习方式.将算法按照学习方式分类是一个不错的 ...

  • 五大常用穴位,解决生活常见问题,这些体质...

    五大常用穴位,解决生活常见问题,这些体质的人可轻松调理! 1.胃热导致嘴里有异味怎么办?--中医妙招--内庭穴 凡是胃火引起的牙痛.咽喉痛.鼻出血.口臭都可以帮助你解决: 2.肾虚无力怎么办?--中医 ...

  • 五大常用穴位,解决生活常见问题,这些体质的人可轻松调理!

    五大常用穴位,解决生活常见问题,这些体质的人可轻松调理! 1.胃热导致嘴里有异味怎么办?--中医妙招--内庭穴 凡是胃火引起的牙痛.咽喉痛.鼻出血.口臭都可以帮助你解决: 2.肾虚无力怎么办?--中医 ...

  • 无人机航迹规划常用算法综述

    王 琼1a,1b, 刘美万1a,1b, 任伟建1a,1b, 王天任2 (1. 东北石油大学 a. 电气信息工程学院; b. 黑龙江省网络化与智能控制重点实验室, 黑龙江 大庆 163318;2. 中国 ...

  • 五大常用模型工具,总30种方法介绍

    五大常用模型工具,总30种方法介绍