算法详解——回溯法

一、回溯法概述——问题背景

  回溯法是一种解决约束满足问题的方法,特别适用于解决组合问题、搜索优化问题等。它通过逐步构建候选解决方案并且在这个解决方案不再可能满足约束或条件时进行剪枝和回溯。具体来说,回溯法可以应用于以下类型的问题:

  • 排列和组合问题:例如求解全排列、子集合等问题,回溯法可以系统地生成所有可能的组合并逐一验证。
  • 决策问题:如八皇后问题、数独填充、图的着色问题等,这些问题需要在多个选择中找到符合特定约束的解。
  • 优化问题:如旅行商问题(TSP)和其他需要找到最优解的问题,回溯法可以遍历所有可能的解,找到成本最低或收益最高的解。
  • 分割问题:例如分割等和子集、装箱问题等,需要将集合分割成满足特定条件的多个子集。

二、回溯法思想——基本过程

  回溯法的基本思想是在包含问题所有可能解的解空间树中,采用深度优先搜索策略来探索解决方案。这一过程从解空间树的根节点开始,逐层深入每一个节点进行探索。在探索到任何一个节点时,首先需要判断该节点是否可能包含问题的解。如果判断为是,算法将继续从这个节点深入,探索所有可能的子节点;如果判断为否,则表明以当前节点为根的子树不会包含问题的有效解,因此无需进一步探索这一路径。

  这时,算法将执行“剪枝”操作,即停止当前路径的进一步探索并退回到其父节点,继续探索其他可能的子节点。通过这种方式,回溯法避免了无效搜索和不必要的计算,从而提高了搜索效率。整个过程不断重复,直到探索完整个解空间树或找到满足条件的解为止。这种策略确保了算法可以系统地覆盖所有可能的解决方案,同时在不满足条件的情况下及时撤退,节省资源。

三、回溯法应用——四皇后问题

   N N N 皇后问题是一种经典的组合优化问题,目标是在一个 N × N N×N N×N 的棋盘上放置 N N N 个皇后棋子,使得这些皇后彼此之间不发生冲突。在国际象棋中,皇后可以在水平、垂直或任意45°斜线方向上移动。因此,解决这一问题的关键在于确保任意两个皇后不能位于同一行、同一列或同一对角线上。为了达成这一目标,我们需要找到一种放置方法,使得棋盘上的每一行、每一列以及所有的主要和次要对角线上都至多只有一个皇后。解决这一问题可以帮助研究和理解更广泛的约束满足和搜索优化问题,同时也是探索算法设计和问题求解技巧的一种方式。如下图即使四皇后问题的一种解:

在这里插入图片描述

  四皇后问题可以通过构建和探索一个解空间树来求解。解空间树是一个抽象结构,用于表示所有可能的解决方案路径。在四皇后问题中,每个节点代表棋盘的一个状态,即某些皇后已经放置在棋盘上的位置。根节点是一个空棋盘,而每个子节点表示在棋盘上新增一个皇后的尝试。解空间树的每一层对应于棋盘的一行,其中每个节点尝试将一个皇后放在那一行的不同列中。我们从根节点开始,按照深度优先的策略探索这棵树。

解空间树的探索过程

  1. 根节点与层次结构:

  根节点代表一个空棋盘,即开始状态。从这里出发,第一层的四个子节点分别尝试在第一行的四列中放置一个皇后。每个子节点又将生成自己的子节点,这些子节点尝试在第二行放置皇后,而且必须确保不与第一行的皇后冲突。

  1. 深度优先搜索与回溯:

  搜索从根节点开始,深入到解空间树的第一层,尝试在第一行的每一列中放置一个皇后。对于每个位置,如果安全,则递归地进入下一层,也就是下一行,尝试放置另一个皇后。

  • 安全性检查:在尝试在棋盘的某行某列放置皇后之前,会检查该位置是否与已放置的皇后有列冲突或对角线冲突。

  • 递归深入:如果当前节点(即棋盘配置)安全,则在下一层继续放置皇后。

  • 回溯:如果在当前行无法找到一个安全的列位置,这表明当前路径不可能导致解决方案,因此算法会回溯到上一层,即上一行,移除上一行的皇后,尝试在其他列放置。

  1. 剪枝:

  在搜索过程中,如果一个节点已确定不可能导致有效解(例如,如果第一行和第二行的皇后在同一列),则无需探索这个节点的任何子节点。这种“剪枝”操作减少了不必要的计算,优化了搜索过程。

  1. 找到解决方案:

  当到达解空间树的底部,即成功在所有四行中放置了皇后,并且所有放置都是安全的,那么这个路径(从根到当前节点的路径)就是一个解决方案。如果未到达底部就无路可走,则需要回溯。

  1. 枚举所有可能的解决方案:

  通过从根节点到解空间树的每一个叶节点的遍历,我们可以找出所有可能的解决方案。棋盘上每一行的每一个合法位置都将被考虑一次,确保全面性。

  通过这种方式,四皇后问题的解空间树提供了一种系统的方法来探索所有可能的解决方案,并有效地避开了不可能的解决方案路径。这不仅显著提高了效率,而且确保了解决方案的完整性。

解决过程与原理

  1. 棋盘初始化:
      棋盘是一个4x4的二维数组,其中的每个元素初始设为0,表示该位置没有放置皇后。棋盘的每一行将尝试放置一个皇后。

  2. 安全性检查:

  在尝试将一个皇后放置在棋盘的某个位置时,必须确保该位置与已放置的其他皇后没有冲突。这涉及到三个方向的检查:

  • 列检查:确保当前列上没有其他皇后。

  • 左上对角线检查:检查从当前位置开始向左上方延伸的对角线上是否有其他皇后。

  • 右上对角线检查:检查从当前位置开始向右上方延伸的对角线上是否有其他皇后。

  这些检查确保任何两个皇后都不会在同一行、列或对角线上,从而避免了相互攻击。

  1. 递归与回溯:

  使用递归函数来尝试在每一行放置一个皇后。对于每一行,函数遍历所有列,并使用安全性检查判断是否可以在当前列放置皇后:

  • 如果当前位置安全,则放置皇后并递归地调用该函数以尝试在下一行放置另一个皇后。

  • 如果成功在所有行放置了皇后,则当前的棋盘配置是一个有效解。

  • 如果在某行中找不到安全的列来放置皇后,则函数将回溯到上一行,移除那一行的皇后,并尝试下一个列位置。

  • 这个过程将持续递归和回溯,直到所有可能的行和列的组合都被尝试过。

  1. 打印解决方案:

  一旦找到一个有效的棋盘配置,即所有皇后都安全地放置,便打印该配置。如果解空间中存在多个解,每个解都会被打印出来。

Python代码实现

def is_safe(board, row, col):# 检查列冲突for i in range(row):if board[i][col] == 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, -1, -1), range(col, len(board))):if board[i][j] == 1:return Falsereturn Truedef solve_n_queens(board, row):if row == len(board):print_solution(board)return Truesolution_found = Falsefor col in range(len(board)):if is_safe(board, row, col):board[row][col] = 1if solve_n_queens(board, row + 1):solution_found = Trueboard[row][col] = 0return solution_founddef print_solution(board):for row in board:print(" ".join('Q' if x == 1 else '.' for x in row))print("")def main():n = 4board = [[0] * n for _ in range(n)]if not solve_n_queens(board, 0):print("没有找到解决方案")main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/691259.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物联网到底物联了个啥?——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网,这个听起来似乎颇具科技感和未来感的词汇,其实早已悄然渗透到我们生活的方方面面。从智能家居到智慧城市,从工业自动化到医疗健康,物联网技术正在以其独特的魅力改变着我们的生活方式…

从头理解transformer,注意力机制(下)

交叉注意力 交叉注意力里面q和KV生成的数据不一样 自注意力机制就是闷头自学 解码器里面的每一层都会拿着编码器结果进行参考,然后比较相互之间的差异。每做一次注意力计算都需要校准一次 编码器和解码器是可以并行进行训练的 训练过程 好久不见输入到编码器&…

自拍欺骗成为流行的身份证件欺诈技术

据 Socure 称,文档图像叠加是 2023 年最流行的身份证件欺诈技术,在所有被拒绝的身份证件中,有 63% 发生这种情况。 自拍欺骗和冒充在与文件相关的身份欺诈中占主导地位 当用户拍摄照片或使用 ID 的屏幕截图图像(而不是提供文档的…

Linux-页(page)和页表

本文在页表方面参考了这篇博客,特别鸣谢! 【Linux】页表的深入分析 1. 页帧和页框 页帧(page frame)是内存的最小可分配单元,也开始称作页框,Linux下页帧的大小为4KB。 内核需要将他们用于所有的内存需求&a…

人工智能能否解决科学问题:Wolfram的视角

引言 在当今AI技术飞速发展的背景下,它在科学研究领域的应用正逐渐深入。从AlphaFold 3的推出到日益复杂的计算模型,AI似乎在向科学家的角色靠拢。然而,美国计算机科学家Stephen Wolfram在一系列讲座和文章中提出了反思:AI真的能…

DDD架构理论详解

文章目录 一、概念入门1. 概念简介2. DDD的核心理念3. 范式4. 模型5. 框架6. 方法论7. 软件设计的主要活动 二、DDD核心理论1. Domain领域层都包含什么?2. 聚合、实体和值对象3. 仓储,封装持久化数据4. 适配(端口),调用…

Python-VBA函数之旅-str函数

目录 一、str函数的常见应用场景 二、str函数使用注意事项 三、如何用好str函数? 1、str函数: 1-1、Python: 1-2、VBA: 2、推荐阅读: 个人主页: https://myelsa1024.blog.csdn.net/ 一、str函数的常…

Uniapp 自定义弹窗

布局 <view><view v-if"show" class"popup"><view class"popup-box"><view>支付方式:{{way}}</view><view>停车费用:{{money}}</view><view class"btn-box"><view class"ca…

从零开始详解OpenCV条形码区域分割

前言 在识别二维码之前&#xff0c;首先要划分出二维码的区域&#xff0c;在本篇文章中将从零开始实现二维码分割的功能&#xff0c;并详细介绍用到的方法。 我们需要处理的图像如下&#xff1a; 完整代码 首先我们先放出完整代码&#xff0c;然后根据整个分割流程介绍用到…

ESP32-C3-MINI-1

https://www.espressif.com.cn/sites/default/files/documentation/esp32-c3-mini-1_datasheet_cn.pdf 芯片 https://files.seeedstudio.com/wiki/XIAO_WiFi/Resources/esp32-c3_datasheet.pdf 结果参考&#xff1a; https://blog.csdn.net/iamxxdd/article/details/12386419…

6818Linux内核--Bootloader应用分析

Bootloader应用分析 一个嵌入式 Linux 系统从软件的角度看通常可以分为四个层次&#xff1a; 引导加载程序。包括固化在固件( firmware )中的 boot 代码(可选)&#xff0c;和 Boot Loader 两大部分。 Linux 内核。特定于嵌入式板子的定制内核以及内核的启动参数。 文件系统…

npm无法安装node-sass 的问题

安装 node-sass 的问题呈现&#xff1a;4.9.0版本无法下载 Downloading binary from https://github.com/sass/node-sass/releases/download/v4.9.0/win32-x64-72_binding.node Cannot download "https://github.com/sass/node-sass/releases/download/v4.9.0/win32-x64-…