zoukankan      html  css  js  c++  java
  • 回溯算法

    回溯算法类似于枚举过程,所不同的是,当发现现有的解已经不构成可行解时,回溯算法会退回到之前一个满足条件的节点(及时止损),继续尝试其他可能,从而大大减小了搜索空间。比如下面的四皇后问题。

    img

    解题思路通常如下:

    result = []
    def backtrack(路径, 选择列表):
        if 不可行解:
            return
        
        if 满足结束条件:
            result.add(路径)
            return
    
        for 选择 in 选择列表:
            做选择
            backtrack(路径, 选择列表)
            撤销选择
    

    由于每次做选择的时候都要遍历当前条件下所有可能的选择,所以需要有一个撤销选择的操作。

    太深的递归可能会造成栈溢出,而且也有效率问题,可以借助额外的栈实现非递归算法:

    待补充...
    

    全排列问题

    求n个不重复数的所有全排列。

    img

    借助上文的模板,路径就是不同的排列,选择是路径外的数字,结束条件是路经长为n,因为候选解中已经确定为不相同的数字,所以不存在不可行解。

    不推荐的例子:

    result = []
    n = 3
    
    
    def backtrack(path: List[int], node: List[int]):
        if len(path) == n:
            result.append(path)
            return
    
        for x in node:
            path_ = path.copy()
            path_.append(x)
            node_ = node.copy()
            node_.remove(x)
            backtrack(path_, node_)
    
    
    backtrack([], list(range(n)))
    print(result)
    

    回溯算法的难点是如何设计路径和维护候选解集,设计的不好就容易造成实现起来复杂而且效率也不够高。比如以下给定没有重复数字的序列,返回所有可能的排列

    输入: [1,2,3]
    输出:
    [
    [1,2,3],
    [1,3,2],
    [2,1,3],
    [2,3,1],
    [3,1,2],
    [3,2,1]
    ]

    候选解并不一定要显示的给出,由于Python的可变对象的问题,通过当前的path推断可选的集合是更常用的选择。

    class Solution:
        def permute(self, nums: List[int]) -> List[List[int]]:
            ans = list()
            n = len(nums)
    
            def backtrack(path):
                if len(path) == n:
                    ans.append(path)
                for x in nums:
                    if x not in path:
                        backtrack(path+[x])
            backtrack([])
            return ans
    

    但如果是包含重复数字的排列,就不能简单的用重复数字找出候选集,此时就需要一个额外的visit列表记录该位置是否被访问过。

    class Solution:
        def permuteUnique(self, nums: List[int]) -> List[List[int]]:
            nums.sort()
            n = len(nums)
            ans = list()
    
            def backtrack(path: List[int], visit: List[bool]) -> None:
                if len(path) == n:
                    ans.append(path)
                else:
                    for i in range(n):
                        if (visit[i] == True or (i > 0 and nums[i] == nums[i-1] and visit[i-1] == False)):
                            pass
                        else:
                            visit[i] = True
                            backtrack(path+[nums[i]], visit)
                            visit[i] = False
            backtrack([], [False]*n)
            return ans
    
  • 相关阅读:
    训练深度学习网络时候,出现Nan 或者 震荡
    Jupyter Notebook 的快捷键
    pyspark RandomForestRegressor 随机森林回归
    深度学习图像标注工具VGG Image Annotator (VIA)使用教程
    python 中 with 用法
    python 报错 SyntaxError: Non-ASCII character
    YOLO 详解
    Spark与Pandas中DataFrame对比
    利用WGET下载文件,并保存到指定目录
    http 三次握手
  • 原文地址:https://www.cnblogs.com/lepeCoder/p/14006672.html
Copyright © 2011-2022 走看看