当前位置: 首页 > news >正文

回溯算法及其应用

回溯是一种常见的算法思想,用于解决许多优化问题。该算法的核心思想是穷举所有可能的解决方案,然后通过剪枝来减少不必要的计算,以获得最优解。

回溯算法常用于求解组合、排列、子集和等问题。通常情况下,回溯算法需要递归地搜索问题的解空间,并在搜索过程中记录可能的解决方案。如果找到了一个可行的解决方案,则返回该解决方案。如果没有找到解决方案,则回溯并尝试其他可能的解决方案,直到所有可能的解决方案都被尝试过。

以下是一个简单的JavaScript回溯算法示例,用于寻找一个数列中所有可能的子集:

function subsets(nums) {const res = [];const backtrack = (start, path) => {res.push(path.slice());for (let i = start; i < nums.length; i++) {path.push(nums[i]);backtrack(i + 1, path);path.pop();}}backtrack(0, []);return res;
}console.log(subsets([1, 2, 3])); // [[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]

在此示例中,我们定义了一个backtrack函数来递归搜索解空间。start参数表示在搜索过程中从哪个位置开始搜索,path参数表示当前搜索路径上的所有元素。在每个递归调用中,我们首先将当前路径添加到结果数组res中,然后从start位置开始循环遍历剩余元素,并尝试将其添加到当前路径中。完成搜索后,我们需要回溯并尝试其他可能的解决方案。

接下来,我们来看一个更实际的应用场景:解决数独问题。

数独是一种流行的逻辑游戏,玩家需要在一个九宫格中填入数字,保证每一行、每一列和每一个小九宫格中的数字都不重复。数独问题可以用回溯算法来求解。下面是一个JavaScript实现的示例代码:

function solveSudoku(board) {const ROWS = 9, COLS = 9;const BOXES = [[0, 0], [0, 3], [0, 6],[3, 0], [3, 3], [3, 6],[6, 0], [6, 3], [6, 6]];const isValid = (row, col, num) => {for (let i = 0; i < ROWS; i++) {if (board[i][col] === num) return false;if (board[row][i] === num) return false;}const boxRow = Math.floor(row / 3) * 3;const boxCol = Math.floor(col / 3) * 3;for (let i = boxRow; i < boxRow + 3; i++) {for (let j = boxCol; j < boxCol + 3; j++) {if (board[i][j] === num) return false;}}return true;}const backtrack = (row, col) => {if (col === COLS) {row++;col = 0;}if (row === ROWS) {return true;}if (board[row][col] !== '.') {return backtrack(row, col + 1);}for (let num = 1; num <= 9; num++) {if (isValid(row, col, String(num))) {board[row][col] = String(num);if (backtrack(row, col + 1)) {return true;}board[row][col] = '.';}}return false;}backtrack(0, 0);
}const board = [['5', '3', '.', '.', '7', '.', '.', '.', '.'],['6', '.', '.', '1', '9', '5', '.', '.', '.'],['.', '9', '8', '.', '.', '.', '.', '6', '.'],['8', '.', '.', '.', '6', '.', '.', '.', '3'],['4', '.', '.', '8', '.', '3', '.', '.', '1'],['7', '.', '.', '.', '2', '.', '.', '.', '6'],['.', '6', '.', '.', '.', '.', '2', '8', '.'],['.', '.', '.', '4', '1', '9', '.', '.', '5'],['.', '.', '.', '.', '8', '.', '.', '7', '9']
];solveSudoku(board);console.log(board);

在这个示例代码中,我们首先定义了一些常量和辅助函数。isValid函数用于检查当前位置是否可以填入指定的数字。backtrack函数则是回溯算法的核心,它用于递归地搜索解空间,并在搜索过程中记录可能的解,然后验证这个解是否符合要求。如果符合要求,则继续搜索下一步可能的解;如果不符合要求,则回溯到上一步,重新选择其他可能的解。

在数独问题中,我们从左到右、从上到下依次遍历每一个格子。对于每一个空格,我们依次尝试填入1到9的数字,并检查填入的数字是否合法。如果合法,则继续搜索下一个空格;如果不合法,则回溯到上一个空格重新尝试填入其他数字。

通过回溯算法,我们可以找到数独问题的一个解,如果数独问题有多个解,回溯算法也可以找到所有的解。在这个示例代码中,我们使用了递归的方式实现回溯算法。当找到一个解时,函数返回true,表示已经找到解;当所有可能的解都被尝试过后,函数返回false,表示没有找到解。

回溯算法的时间复杂度一般较高,因为它需要搜索所有可能的解空间。对于数独问题,回溯算法的时间复杂度取决于解的数量,一般来说解的数量不会太多,因此回溯算法是一个有效的求解方法。

总之,回溯算法是一种常用的求解问题的方法,它可以用于求解各种类型的问题,包括数独、八皇后、0/1背包等等。在实际应用中,我们可以结合其他算法和数据结构来优化回溯算法的效率,例如剪枝、记忆化搜索等。

下面是完整的示例代码:

// 数独问题的解决函数
function solveSudoku(board) {// 遍历数独表格for (let i = 0; i < 9; i++) {for (let j = 0; j < 9; j++) {// 如果当前格子为空if (board[i][j] === ".") {// 尝试填入1到9的数字for (let num = 1; num <= 9; num++) {// 如果填入的数字合法if (isValid(board, i, j, num)) {// 填入数字board[i][j] = num.toString();// 递归调用解决函数if (solveSudoku(board)) {// 如果找到解,则返回truereturn true;} else {// 如果没有找到解,则回溯board[i][j] = ".";}}}// 如果尝试了所有的数字都无法得到解,则返回falsereturn false;}}}// 如果遍历完整个数独表格,都没有返回true,则说明已经找到解return true;
}// 检查填入的数字是否合法
function isValid(board, row, col, num) {// 检查行是否合法for (let i = 0; i < 9; i++) {if (board[row][i] === num.toString()) {return false;}}// 检查列是否合法for (let j = 0; j < 9; j++) {if (board[j][col] === num.toString()) {return false;}}// 检查3x3方格是否合法let boxRow = Math.floor(row / 3) * 3;let boxCol = Math.floor(col / 3) * 3;for (let i = boxRow; i < boxRow + 3; i++) {for (let j = boxCol; j < boxCol + 3; j++) {if (board[i][j] === num.toString()) {return false;}}}// 如果行、列、3x3方格都没有重复的数字,则返回truereturn true;
}// 测试代码
let board = [["5", "3", ".", ".", "7", ".", ".", ".", "."],["6", ".", ".", "1", "9", "5", ".", ".", "."],[".", "9", "8", ".", ".", ".", ".", "6", "."],["8", ".", ".", ".", "6", ".", ".", ".", "3"],["4", ".", ".", "8", ".", "3", ".", ".", "1"],["7", ".", ".", ".", "2", ".", ".", ".", "6"],[".", "6", ".", ".", ".", ".", "2", "8", "."],[".", ".", ".", "4", "1", "9", ".", ".", "5"],[".", ".", ".", ".", "8", ".", ".", "7", "9"],
];
if (solveSudoku(board)) {console.log(board);
} else {console.log("No solution");
}

上述代码实现了一个求解数独问题的函数solveSudoku上述代码实现了一个求解数独问题的函数solveSudoku,该函数使用了回溯算法的思想。具体实现过程如下:

  1. 遍历数独表格的每一个格子,如果当前格子为空,则尝试填入1到9的数字。
  2. 如果填入的数字合法(即在行、列、3x3方格中都没有重复的数字),则将该数字填入当前格子。
  3. 递归调用solveSudoku函数,继续填写下一个空格。
  4. 如果在下一个空格中找到了解,则返回true,表示已经找到解。
  5. 如果在下一个空格中没有找到解,则回溯到当前格子,将当前格子重新设为".",并尝试填入下一个数字。
  6. 如果尝试了所有的数字都无法得到解,则返回false。

相关文章:

回溯算法及其应用

回溯是一种常见的算法思想&#xff0c;用于解决许多优化问题。该算法的核心思想是穷举所有可能的解决方案&#xff0c;然后通过剪枝来减少不必要的计算&#xff0c;以获得最优解。 回溯算法常用于求解组合、排列、子集和等问题。通常情况下&#xff0c;回溯算法需要递归地搜索…...

如何一步步打造完美的成绩查询系统平台?

想要搭建一个高效的在线发布成绩查询系统平台&#xff0c;首先需要了解哪些技术和工具是必备的。本文将为您介绍一些主流的技术和工具&#xff0c;帮助您快速搭建一个稳定、安全、易用的成绩查询系统。 想要制作在线成绩查询系统平台有两种方式&#xff0c;第一种是直接使用易…...

P1026 [NOIP2001 提高组] 统计单词个数

题目描述 给出一个长度不超过 200200 的由小写英文字母组成的字母串&#xff08;该字串以每行 2020 个字母的方式输入&#xff0c;且保证每行一定为 2020 个&#xff09;。要求将此字母串分成 &#xfffd;k 份&#xff0c;且每份中包含的单词个数加起来总数最大。 每份中包含…...

CTFHub | eval执行

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…...

IP协议头

IP 4位版本号&#xff08;version&#xff09;4位头部长度&#xff08;header length&#xff09;8位服务类型&#xff08;Type Of Service&#xff09;16位总长度&#xff08;total length&#xff09;16位标识&#xff08;id&#xff09;3位标志字段13位分片偏移&#xff08;…...

【xxl-job定时任务框架详解】

一,分布式任务调度 基本概念 分布式任务调度是一种用于在分布式环境中调度和执行任务的技术。在分布式系统中,由于存在多台服务器、多个进程和线程并行执行,因此需要一种机制来协调和管理任务的执行,避免任务冲突、重复执行、负载不均衡等问题。分布式任务调度通常由一个…...

7、在vscode上利用cmake构建多文件C++工程

文章目录 &#xff08;1&#xff09;创建如下工程文件夹&#xff1a;其中头文件放在include文件夹中&#xff0c;源文件放在src文件夹中&#xff08;2&#xff09;在vscode上打开工程文件夹&#xff0c;在对应的文件夹内建立相应的文件1&#xff09;目录结构2&#xff09;各文件…...

Linux操作系统网络模块

Linux操作系统的网络模块是负责网络通信的核心部分。它通过实现各种协议和算法&#xff0c;使得计算机能够在网络中进行数据交换和通信。网络模块主要包括以下几个方面的功能&#xff1a; &#xff08;1&#xff09;IP协议栈&#xff1a;负责处理网络层的数据包&#xff0c;实…...

不同批次板子采集到的传感器压力值不同

问题描述&#xff1a; M340B空压机主控板在接正常压力气源时&#xff0c;显示屏显示压力值过高并报警。 问题排查&#xff1a; 确认可能的故障点&#xff1a;压力传感器、硬件电路&#xff08;供电电路、分压电路、ADC采样电路等&#xff09;、单片机、软件&#xff1b; 排…...

设计模式--原型模式

目录 基本介绍 传统方式克隆 原型模式改进 浅拷贝和深拷贝 浅拷贝的介绍 深拷贝的介绍 原型模式的注意事项和细节 基本介绍 (1) 原型模式(prototype模式): 用原型实例指定创建对象的种类 并且通过拷贝这些原型 创建新的对象 (2) 原型模式是一种创建型设计模式 允许一个…...

C++智能指针shared_ptr详解

智能指针shared_ptr详解 一、简介二、底层原理2.1、引用计数2.2、shared_ptr的构造和析构2.3、shared_ptr的共享和拷贝2.4、循环引用问题 三、shared_ptr的使用3.1、创建一个shared_ptr3.2、共享一个shared_ptr3.3、使用删除器3.4、解除关联 四、使用示例总结 一、简介 C智能指…...

家政服务APP小程序开发功能详解

随着人们生活水平的提高&#xff0c;对家政服务的要求也越来越高。而传统的到家政公司寻找服务人员的方法显然已经无法满足人们需求&#xff0c;取而代之的是线上预约家政服务。家政服务App小程序软件可以满足用户在线预约&#xff0c;还可以根据自己的需求定制家政服务、选择家…...

【C++】deque的实现原理简单介绍

前言 deque被称为双端队列&#xff0c;它的出现主要是为了结合vector和list的优点并减小它们的缺点&#xff0c;实际上deque确实结合了vector和list的优点减小了它们的缺点&#xff0c;但是它的结合也让它自己的优点没有原始的vector和list那么极致&#xff0c;导致deque变得很…...

UWB隧道人员定位技术应用,施工作业安全精准保障

隧道施工的安全不仅关系到工程项目的质量和施工效率&#xff0c;也关系到我国的资金安全、施工人员和人民的生命财产安全。如何有效加强隧道施工的安全管理能力&#xff0c;成为隧道施工企业管理者最关心的问题。国家铁道局在《关于加强铁路隧道工程安全工作的若干意见》中指出…...

15.2 矩阵链乘法

1.代码 public class MatrixChainMultiplication {public static void main(String[] args) { // 在该代码中&#xff0c;我们首先创建了两个n * n的矩阵m和s&#xff0c;分别用于记录最优值和分割点。 其中m 矩阵 通过i j 来显示在i到j的矩阵链中最优解 // // …...

向隐形冠军学习:聚焦人效,用时间管理提效益

注&#xff1a; 本文来源于盖雅工场联合创始人兼CEO 章新波 在2023狮山论坛“ 向隐形冠军学习&#xff1a; 聚焦人效&#xff0c;用时间管理提效益 ”的主题分享。 文&#xff5c;章新波 整理 &#xff5c;盖雅学苑 在人力资源行业以及各大企业&#xff0c;「人效」这个词…...

Protocol Buffers Go Generated Code Guide

Protocol Buffers Go 代码生成指南 本主题准确描述了协议缓冲区编译器为任何给定的协议定义生成的Go代码。 编译器调用 协议缓冲区编译器需要一个插件来生成Go 代码。使用Go 1.16或更高版本安装&#xff0c;方法是运行&#xff1a; go install google.golang.org/protobuf/…...

Python VTK STL 映射三维模型表面距离

目录 前言&#xff1a; 效果&#xff1a; 实现步骤&#xff1a; Code: 前言&#xff1a; 本文介绍了Python VTK映射三维模型表面距离&#xff0c;通过如何使用VTK计算两个三维模型(stl)的表面距离&#xff0c;并将其距离值以颜色映射到模型&#xff0c;可用于对比 两相模型…...

C# 异常处理机制和常见的异常类型

在 C# 中&#xff0c;异常处理是一个非常重要的概念&#xff0c;它可以让我们在程序发生错误时进行有效的处理&#xff0c;使程序具备更好的鲁棒性。C# 异常处理机制基于 try-catch-finally 语句块&#xff0c;其基本用法如下&#xff1a; try {// 可能会抛出异常的代码 } cat…...

【0187】客户端身份验证配置文件视图之pg_hba_file_rules

文章目录 1. 客户端身份验证配置文件视图2. 视图效果相关阅读: 【0179】配置PostgreSQL以允许远程连接 【0180】PG内核通过pg_hba.conf完成客户端认证(1) 【0181】PG内核通过pg_hba.conf完成客户端认证(2)...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...