首页 > 编程语言 >【技术积累】算法中的回溯算法【一】

【技术积累】算法中的回溯算法【一】

时间:2023-06-12 15:33:22浏览次数:34  
标签:积累 算法 board 回溯 path col row

回溯算法是什么

回溯算法是一种用于求解在某个搜索空间中的问题的算法。它基本思想是从问题的某一种状态开始不断地尝试各种可能的选择,直到找到一种满足问题要求的解或者发现这些选择都无法满足要求时,就回到上一个状态,尝试其他的选择。

回溯算法通常采用递归的方法实现,它会不断地递归调用自身,同时通过参数来模拟每一种选择的结果,并在递归返回时撤销这种选择,继续寻找其他可能的选择。

回溯算法通常用于求解组合问题、排列问题、选择问题等,例如求解 n 皇后问题、数独问题等。在实际应用中,回溯算法往往需要通过一些优化方法来减少搜索空间,以达到更高的效率和更快的求解速度。

回溯算法的应用场景有哪些

回溯算法的应用场景包括但不限于:

  1. 生成排列和组合问题,如全排列、组合问题等。

  2. 解决搜索问题,如图的遍历、迷宫问题等。

  3. 解决约束条件满足问题,如数独、八皇后、数塔问题等。

  4. 解决最优化问题,如背包问题、旅行商问题等。

  5. 解决字符串匹配问题,如正则表达式匹配、通配符匹配等。

  6. 解决人工智能领域的问题,如游戏博弈、机器学习等。

  7. 解决决策问题,如规划和调度问题等。

  8. 解决网络流问题。

总之,回溯算法可以解决许多复杂的问题,在实际应用中具有广泛的应用

回溯算法的优点和缺点是什么

回溯算法的优点:

  1. 适用范围广:回溯算法可以解决很多问题,如搜索、排列组合、八皇后、数独等。
  2. 算法思路简单:回溯算法的思路简单,易于理解和实现。
  3. 可以找到所有解:回溯算法可以找到所有的解,不会漏掉任何一个解。

回溯算法的缺点:

  1. 时间复杂度高:回溯算法的时间复杂度很高,因为它需要遍历所有的解空间,搜索时间可能会很长。
  2. 空间复杂度高:回溯算法的空间复杂度也很高,因为它需要维护一个状态树,存储所有的状态和路径。
  3. 可能会陷入死循环:如果回溯算法没有正确地剪枝,可能会陷入死循环,导致程序无法结束。

回溯算法的时间复杂度和空间复杂度是多少?

回溯算法的时间复杂度和空间复杂度都与问题规模和决策树的分支情况有关。

时间复杂度: 在最坏情况下,回溯算法需要遍历整个决策树,即每个节点都需要访问一次,所以时间复杂度为O(b^d),其中b是分支因子,d是决策树的深度。因此,回溯算法的时间复杂度通常比较高,在面对大规模问题时可能需要较长时间。

空间复杂度: 在回溯算法中,需要维护一个候选解的状态,通常使用递归调用栈来实现。因此,空间复杂度也与决策树的深度相关。在最坏情况下,决策树的深度与问题规模成正比,因此空间复杂度为O(d),其中d为决策树的深度。如果在实现回溯算法时没有使用递归,可以使用循环和栈来代替递归调用栈,这样可以避免递归调用栈导致的空间限制,但是实现起来相对复杂。

回溯算法解决八皇后问题

八皇后问题是计算机科学中的经典问题,涉及将八个皇后放置在一个8x8的棋盘上,以使没有两个皇后相互威胁。这意味着不能将两个皇后放在同一

行、列或对角线上。
 

  1. 定义问题:八皇后问题涉及将八个皇后放置在一个8x8的棋盘上,以使没有两个皇后相互威胁。
  2. 创建棋盘:创建一个8x8的棋盘并将所有方格初始化为0。
  3. 放置皇后:从第一列开始,在第一行放置一个皇后。
  4. 检查冲突:检查皇后是否与棋盘上的任何其他皇后发生冲突。如果存在冲突,则将皇后移到同一列中的下一行。
  5. 重复步骤3和4:继续在每一列中放置皇后并检查冲突,直到所有皇后都放置在棋盘上。
  6. 回溯:如果在列中没有有效的皇后位置,则回溯到上一列并将皇后移到该列的下一行。重复此过程,直到找到有效的解决方案。
function solveEightQueens(board, col): 
  if col >= 8: 
    return true 
 
  for row in range(0, 8): 
    if isSafe(board, row, col): 
      board[row][col] = 1 
      if solveEightQueens(board, col+1): 
        return true 
      board[row][col] = 0 
 
  return false 
 
function isSafe(board, row, col): 
  for i in range(0, col): 
    if board[row][i] == 1: 
      return false 
 
  for i, j in zip(range(row, -1, -1), range(col, -1, -1)): 
    if board[i][j] == 1: 
      return false 
 
  for i, j in zip(range(row, 8, 1), range(col, -1, -1)): 
    if board[i][j] == 1: 
      return false 
 
  return true 
 
// initialize board to all 0's 
board = [[0 for x in range(8)] for y in range(8)] 
 
// solve the problem 
solveEightQueens(board, 0)

回溯算法解决数独问题

数独是一个9x9的网格,被分成9个小的3x3的网格。目标是填充网格,使每行、每列和每个3x3网格都包含1到9的数字,且没有重复。

  1. 从一个空的数独网格开始。
  2. 在网格中找到一个空的单元格。
  3. 尝试在该单元格中放置1到9的所有数字。
  4. 如果数字有效(即不违反任何数独规则),则移动到下一个空的单元格并重复步骤3。
  5. 如果数字无效,则尝试下一个数字。
  6. 如果所有数字都已尝试且没有一个有效,则回溯到上一个单元格并尝试下一个数字。
  7. 重复步骤3到6,直到整个网格都被填满。
function solveSudoku(grid):
  for i in range(9):
    for j in range(9):
      if grid[i][j] == 0:
        for k in range(1, 10):
          if isValid(grid, i, j, k):
            grid[i][j] = k
            if solveSudoku(grid):
              return True
            grid[i][j] = 0
        return False
  return True
 function isValid(grid, row, col, num):
  for i in range(9):
    if grid[row][i] == num:
      return False
    if grid[i][col] == num:
      return False
    if grid[3 * (row // 3) + i // 3][3 * (col // 3) + i % 3] == num:
      return False
  return True

solveSudoku函数接受一个9x9的网格作为输入,并在数独可解时返回True,否则返回False。它使用嵌套循环来迭代网格中的所有单元格。如果一个单元格为空(即其值为0),它使用另一个循环尝试在该单元格中放置1到9的所有数字。如果数字有效(即不违反任何数独规则),则移动到下一个空的单元格并重复该过程。如果数字无效,则尝试下一个数字。如果所有数字都已尝试且没有一个有效,则回溯到上一个单元格并尝试下一个数字。isValid函数通过检查数字是否违反任何数独规则(即是否已经存在于同一行、列或3x3网格中)来检查数字是否有效。

回溯算法解决全排列问题

给定一个数字序列,要求输出所有可能的排列组合。

  1. 定义一个递归函数,用于生成所有可能的排列组合。
  2. 在递归函数中,先判断当前生成的排列是否已经包含了所有数字,如果是,则输出当前排列并返回。
  3. 如果当前排列还没有包含所有数字,就从剩余的数字中选择一个,加入当前排列中,并继续递归生成下一个数字的排列。
  4. 在递归完成后,需要将加入的数字从当前排列中移除,以便继续生成其他排列组合。
function backtrack(nums, path, res):
    if len(path) == len(nums):
        res.append(path)
        return
    for num in nums:
        if num not in path:
            path.append(num)
            backtrack(nums, path[:], res)
            path.pop()

backtrack函数接受三个参数:nums表示给定的数字序列,path表示当前生成的排列,res表示所有可能的排列组合。在函数中,首先判断当前生成的排列是否已经包含了所有数字,如果是,则将当前排列加入结果集中并返回。如果当前排列还没有包含所有数字,就从剩余的数字中选择一个,加入当前排列中,并继续递归生成下一个数字的排列。在递归完成后,需要将加入的数字从当前排列中移除,以便继续生成其他排列组合。

回溯算法解决组合问题

给定一个数组和一个目标值,从数组中选取元素使得它们的和等于目标值。

  1. 定义一个递归函数,用于生成所有可能的组合。
  2. 在递归函数中,先判断当前组合的元素和是否等于目标值,如果是,则输出当前组合并返回。
  3. 如果当前组合的元素和小于目标值,就从剩余的元素中选择一个,加入当前组合中,并继续递归生成下一个元素的组合。
  4. 在递归完成后,需要将加入的元素从当前组合中移除,以便继续生成其他组合。
function backtrack(nums, target, start, path, res):
    if sum(path) == target:
        res.append(path)
        return
    for i in range(start, len(nums)):
        if sum(path) + nums[i] > target:
            continue
        path.append(nums[i])
        backtrack(nums, target, i, path[:], res)
        path.pop()

backtrack函数接受五个参数:nums表示给定的数组,target表示目标值,start表示当前开始选择的位置,path表示当前生成的组合,res表示所有可能的组合。在函数中,首先判断当前组合的元素和是否等于目标值,如果是,则将当前组合加入结果集中并返回。如果当前组合的元素和小于目标值,就从剩余的元素中选择一个,加入当前组合中,并继续递归生成下一个元素的组合。在递归完成后,需要将加入的元素从当前组合中移除,以便继续生成其他组合。

回溯算法解决单词搜索问题

在一个二维字符数组中查找给定单词是否存在。

  1. 定义一个递归函数,用于生成所有可能的路径。
  2. 在递归函数中,先判断当前位置是否为单词的最后一个字符,如果是,则返回True。
  3. 如果当前位置不是单词的最后一个字符,则从当前位置向四周扩展,如果扩展的位置是合法的并且没有走过,则将该位置加入当前路径中,并继续递归生成下一个位置的路径。
  4. 在递归完成后,需要将加入的位置从当前路径中移除,以便继续生成其他路径。
  5. 如果所有路径都生成完毕,仍未找到单词,则返回False。

function backtrack(board, word, row, col, path):
    if len(path) == len(word):
        return True
    if row < 0 or row >= len(board) or col < 0 or col >= len(board[0]) or board[row][col] != word[len(path)]:
        return False
    temp = board[row][col]
    board[row][col] = "#"
    res = backtrack(board, word, row + 1, col, path + [(row, col)]) or backtrack(board, word, row - 1, col, path + [(row, col)]) or backtrack(board, word, row, col + 1, path + [(row, col)]) or backtrack(board, word, row, col - 1, path + [(row, col)])
    board[row][col] = temp
    return res
 def exist(board, word):
    for i in range(len(board)):
        for j in range(len(board[0])):
            if backtrack(board, word, i, j, []):
                return True
    return False

 

 

backtrack函数接受四个参数:

  1. board表示给定的二维字符数组
  2. word表示要查找的单词
  3. row和col表示当前位置的行列坐标
  4. path表示当前生成的路径。

在函数中,首先判断当前位置是否为单词的最后一个字符,如果是,则返回True。

如果当前位置不是单词的最后一个字符,则从当前位置向四周扩展,如果扩展的位置是合法的并且没有走过,则将该位置加入当前路径中,并继续递归生成下一个位置的路径。

在递归完成后,需要将加入的位置从当前路径中移除,以便继续生成其他路径。如果所有路径都生成完毕,仍未找到单词,则返回False。

 

exist函数接受两个参数:

  1. board表示给定的二维字符数组
  2. word表示要查找的单词。

在函数中,遍历二维字符数组中的每一个位置,如果从该位置开始可以找到单词,则返回True。

如果遍历完整个二维字符数组,仍未找到单词,则返回False。

标签:积累,算法,board,回溯,path,col,row
From: https://www.cnblogs.com/yyyyfly1/p/17474714.html

相关文章

  • 算法题:求解斐波那契数列
    概念:斐波那契数列是指以0,1开始,之后每一项都等于前两项之和的数列,即:0,1,1,2,3,5,8,13,21,34,55,89,144……以此类推。这个数列最早是由13世纪意大利数学家斐波那契提出的,并在数学、自然科学和计算机科学等领域有着广泛的应用。题目:若有一只兔子,它每个月生一只小兔子,而小兔子......
  • 算法练习-day5
    哈希表242.有效的字母异位词题意:给定两个字符串s和t,编写一个函数来判断t是否是s的字母异位词。注意:若s和t中每个字符出现的次数都相同,则称s和t互为字母异位词。示例:    思路:我们可以先创建一个unordered_map用于记录s中元素出现的次数,然后再遍历t,让t出现元素次数减去s出现......
  • 算法分析期末复习
    算法分析期末复习第一章算法概述基本理论知识课后作业做过的类型渐进阶排序,类似课后作业:1-3输入规模,类似课后作业:1-4,1-5第二章递归与分治基本概念,基本思想递归:直接或间接的调用自身的算法。分治:分治法的子问题间是相互独立的,子问题不包含公共的子问题。......
  • 深度学习降噪专题课:实现WSPK实时蒙特卡洛降噪算法
    大家好~本课程基于全连接和卷积神经网络,学习LBF等深度学习降噪算法,实现实时路径追踪渲染的降噪本课程偏向于应用实现,主要介绍深度学习降噪算法的实现思路,演示实现的效果,给出实现的相关代码线上课程资料:本节课录像回放加QQ群,获得相关资料,与群主交流讨论:106047770本系列文章为......
  • RC4加密算法及Python实现
    一、RC4加密算法原理RC4算法是一种流加密算法,由RonRivest在1987年设计。它的主要特点是简单快速,而且在加密解密过程中使用的密钥长度可变。因此,RC4算法被广泛应用于网络安全领域,如SSL、TLS、WEP、WPA等协议中。RC4算法的加密过程如下:初始化S盒和T数组。S盒是一个256字节的数组,用于......
  • 4.4 分类算法-逻辑回归与二分类以及分类的评估方法
    1逻辑回归的简介1.1简介逻辑回归(LogisticRegression)是机器学习中的一种分类模型,逻辑回归是一种分类算法,虽然名字中带有回归,但是它与回归之间有一定的联系。由于算法的简单和高效,在实际中应用非常广泛。1.2应用场景广告点击率(是否会被点击)是否为垃圾邮件是否患病金融诈......
  • 算法题:球反弹高度问题
    一个球从100米高度自由落下,每次落地反弹回原高度一半。求它在第10次落地时候,共经过多少米? 第十次反弹高度是多少?//设经过路程为sum每次反弹高度为F$f=100;$sum=100;for($i=1;$i<=10;$i++){$f=$f/2;$sum=$sum+$f;}echo"共经过".$sum."米,第10次反......
  • 【LeetCode.384打乱数组】Knuth洗牌算法详解
    前两天看网易面筋得知网易云的随机歌曲播放使用了这个算法,遂找题来做做学习一下打乱数组https://leetcode.cn/problems/shuffle-an-array/给你一个整数数组nums,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是等可能的。实现Solutionclass:Solution......
  • 算法题:百钱买鸡问题
    公鸡5文钱一只母鸡3文钱一只小鸡一文钱3只 问100文钱,要买100只鸡,每种鸡不少于一只 那么100只鸡中,公鸡母鸡小鸡各有多少只//设公鸡数g母鸡数m小鸡数x//那么g*5+m*3+x/3=100文for($g=1;$g<=100;$g++){for($m=1;$m<=100;$m++){for($x=1;$x<=1......
  • 神经网络反向传播算法(BP)
    前面讲了神经网络的前向传播算法,下面再对反向传播算法进行总结。反向传播算法也称为误差逆传播(errorBackPropagation),是指基于梯度下降对神经网络的损失函数进行迭代优化求极小值的过程,它不仅可应用于前馈神经网络,还可以用于其他类型的神经网络。需要注意的是,大家提及到的“BP网......