数据结构与算法:回溯算法约束条件:剪枝详解、示例(C#、C++)与回溯典型例题详解

文章目录

  • 一、约束条件
  • 二、剪枝
  • 三、典型例题
  • 四、常用术语
  • 五、示例
    • N 皇后问题 C# 示例
    • N 皇后问题 C++ 示例
  • 六、常见用用回溯算法解决的问题汇总
    • 组合问题:
    • 图论问题:
    • 棋盘游戏问题:
    • 优化问题:
    • 调度问题:
    • 其他问题:
  • 总结

在这里插入图片描述


回溯算法是一种通过探索所有可能的候选解来找出所有解的算法。在解决一些问题时,我们需要设置一些约束条件,以确保候选解的有效性。这些约束条件在算法中起着非常重要的作用,因为它们定义了一个问题的解空间。通常,我们会使用剪枝技术来减少搜索空间,以提高算法的效率。

本文将详细介绍回溯算法中的约束条件、剪枝技术以及一些典型的回溯问题,还会讨论一些常用的术语。

一、约束条件

在回溯算法中,约束条件是非常重要的,因为它们定义了一个问题的解空间。约束条件必须被满足,一个候选解才被认为是有效的。通常,这些约束条件在算法中被用来进行剪枝,即提前排除那些明显不可能产生解的候选解,从而减少搜索空间。

以 N 皇后问题为例,约束条件如下:

  1. 同一列上的两个皇后不能相互攻击。
  2. 同一斜线(对角线和反对角线)上的两个皇后不能相互攻击。

在 0-1 背包问题中,约束条件如下:

  1. 背包的总容量有限。
  2. 每个物品都有一个重量和价值。

二、剪枝

剪枝是回溯算法中用于减少搜索量的技术。有两种主要的剪枝技术:

  • 前剪枝: 在搜索的早期阶段就排除一些不可能产生有效解的分支。例如,在解决 N 皇后问题时,如果一个皇后已经被放置在某个位置,那么与这个位置在同一行、同一列和同一对角线上的所有其他位置都不能放置皇后。

  • 后剪枝: 在搜索的后期阶段消除那些已经确定不可能产生解的分支。例如,在解决 0-1 背包问题时,如果当前的总重量已经超过背包的容量,那么这个分支可以被剪掉,因为不可能产生一个更优的解。

三、典型例题

1. N 皇后问题: 在 N×N 的棋盘上放置 N 个皇后,使得它们不会相互攻击(即没有两个皇后在同一列、同一行或同一对角线上)。
2. 0-1 背包问题: 给定一组物品,每个物品有一个价值和一个重量,需要选择一些物品放入一个给定容量的背包中,使得背包内物品的总价值最大。
3. 旅行商问题(TSP): 给定一组城市和每两个城市之间的距离,找到一条最短的路径,访问每个城市一次并返回起点。

四、常用术语

1. 候选解: 一个潜在的解,它可能满足所有约束条件。
2. 有效解: 一个候选解,它满足所有约束条件,被认为是实际问题中的解。
3. 搜索空间: 所有可能候选解的集合。
4. 路径/分支: 从初始状态到某个状态的一系列决策的集合。
5. 深度优先搜索(DFS): 一种回溯算法的实现方式,它沿着一个分支深入到不能再深入为止,然后回溯到上一个分叉点继续搜索。

五、示例

下面是 N 皇后问题和 0-1 背包问题的 C# 和 C++ 示例代码。

N 皇后问题 C# 示例

using System;
using System.Collections.Generic;namespace NQueens
{class Program{static void Main(string[] args){int n = 8;SolveNQueens(n);}static void SolveNQueens(int n){int[] board = new int[n];bool[] columns = new bool[n];bool[] diag1 = new bool[2 * n - 1];bool[] diag2 = new bool[2 * n - 1];if (PlaceQueens(board, 0, columns, diag1, diag2)){Console.WriteLine("解决方案:");PrintBoard(board);}else{Console.WriteLine("没有找到解决方案。");}}static bool PlaceQueens(int[] board, int row, bool[] columns, bool[] diag1, bool[] diag2){if (row == board.Length){return true;}for (int col = 0; col < board.Length; col++){if (columns[col] || diag1[row - col + board.Length - 1] || diag2[row + col]){continue;}columns[col] = true;diag1[row - col + board.Length - 1] = true;diag2[row + col] = true;board[row] = col;if (PlaceQueens(board, row + 1, columns, diag1, diag2)){return true;}board[row] = 0;columns[col] = false;diag1[row - col + board.Length - 1] = false;diag2[row + col] = false;}return false;}static void PrintBoard(int[] board){for (int i = 0; i < board.Length; i++){for (int j = 0; j < board.Length; j++){Console.Write(board[j] == i ? "Q " : ". ");}Console.WriteLine();}}}
}

N 皇后问题 C++ 示例

#include <iostream>
#include <vector>using namespace std;void printBoard(const vector<vector<int>>& board) {for (const auto& row : board) {for (int column : row) {cout << column << " ";}cout << endl;}
}bool isSafe(const vector<vector<int>>& board, int row, int col, vector<bool>& columns, vector<bool>& diag1, vector<bool>& diag2) {for (int i = 0; i < row; i++) {if (board[i][col] == 1) {return false;}}for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {if (board[i][j] == 1) {return false;}}for (int i = row, j = col; i < board.size() && j < board[0].size(); i++, j++) {if (board[i][j] == 1) {return false;}}return true;
}bool solveNQueensUtil(vector<vector<int>>& board, int row, vector<bool>& columns, vector<bool>& diag1, vector<bool>& diag2) {if (row == board.size()) {printBoard(board);return true;}for (int col = 0; col < board[0].size(); col++) {if (isSafe(board, row, col, columns, diag1, diag2)) {board[row][col] = 1;columns[col] = true;diag1[row - col + board.size() - 1] = true;diag2[row + col] = true;if (solveNQueensUtil(board, row + 1, columns, diag1, diag2)) return true;board[row][col] = 0;columns[col] = false;diag1[row - col + board.size() - 1] = false;diag2[row + col] = false;}}return false;
}vector<vector<int>> solveNQueens(int n) {vector<vector<int>> board(n, vector<int>(n, 0));vector<bool> columns(n, false);vector<bool> diag1(2 * n - 1, false);vector<bool> diag2(2 * n - 1, false);solveNQueensUtil(board, 0, columns, diag1, diag2);return board;
}int main() {int n = 4;vector<vector<int>> board = solveNQueens(n);return 0;
}

六、常见用用回溯算法解决的问题汇总

回溯算法是一种深度优先搜索的变种,它适用于解决那些需要探索所有可能解的问题。这类问题通常具有递归结构,即一个问题的解空间可以被分解为多个子问题,每个子问题都是原问题的一部分。以下是一些可以用回溯算法解决的问题:

组合问题:

  1. 排列问题(Permutations):给定一组数字,找出所有可能的排列。
  2. 组合问题(Combinations):给定一组数字,找出所有可能的组合。

图论问题:

  1. 最小生成树(MST):在无向图中找到一个包含所有顶点的子图,使得边的总权重最小。
  2. 最大匹配(Maximum Matching):在图中发现最大的匹配集合。
  3. 哈密顿路径(Hamiltonian Path):在图中寻找一条经过所有顶点恰好一次的路径。
  4. 中国邮递员问题(Chinese Postman Problem):寻找一条经过所有边恰好一次的路径,使得总权重最小。

棋盘游戏问题:

  1. 八皇后问题(8 Queens):在 8x8 的棋盘上放置 8 个皇后,使它们互不攻击。
  2. 骑士巡游问题(Knight’s Tour):在棋盘上找到一条骑士访问所有方格恰好一次的路径。

优化问题:

  1. 0-1 背包问题(0-1 Knapsack Problem):给定一组物品,每个物品有一个价值和重量,选择一些物品放入一个给定容量的背包中,使得背包内物品的总价值最大。
  2. 旅行商问题(TSP):寻找一条最短的路径,访问每个城市恰好一次并返回起点。
  3. 表达式求值问题(Evaluate Expression):给定一个包含加、减、乘、除和括号的表达式,计算其值。

调度问题:

  1. 课程调度问题(Course Scheduling):在有限的时间内安排多门课程,满足各种约束条件。
  2. 机器调度问题(Machine Scheduling):在有限的时间内安排多个机器的工作任务,满足各种约束条件。

其他问题:

  1. 子集和问题(Subset Sum):给定一个整数数组和一个目标值,判断是否存在一个子集,其和等于目标值。
  2. 数独问题(Sudoku):在 9x9 的网格中填入数字,使得每行、每列和每个 3x3 子网格中都包含 1 到 9 的所有数字。
  3. 汉诺塔问题(Tower of Hanoi):通过移动盘子从一个塔到另一个塔,同时遵守特定的规则。

回溯算法通过递归地尝试所有可能的解,并在发现当前解不满足要求时回溯到上一个状态,尝试其他可能的解。这种方法适用于解决上述问题,并且可以通过剪枝技术来优化搜索过程,减少不必要的计算。

总结

回溯算法是一种强大的算法,可以用来解决各种问题。通过设置约束条件和使用剪枝技术,我们可以有效地减少搜索空间,提高算法的效率。在实际应用中,回溯算法可以帮助我们解决各种问题,如 N 皇后问题、0-1 背包问题、旅行商问题等。希望这篇博客能帮助你更好地理解回溯算法及其应用。

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

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

相关文章

How to persist LangChain conversation memory (save and load)

题意&#xff1a;如何持久化 LangChain 对话记忆&#xff08;保存和加载&#xff09; 问题背景&#xff1a; Im creating a conversation like so: 我正在创建一个对话&#xff0c;如下所示&#xff1a; llm ChatOpenAI(temperature0, openai_api_keyOPENAI_API_KEY,…

【CTF】BUU BURP COURSE 11

打开靶机之后&#xff0c;显示只能在本地打开&#xff08;一度以为靶机出问题&#xff09;。 解题步骤&#xff1a; 1.分析请求包信息 2.构建本地请求IP X-Real-IP&#xff1a;记录真实客户端IP地址信息&#xff1b; X-Forward-for&#xff1a;记录了请求IP到目标ip所经历的…

新型基坑气膜:施工开挖的得力干将—轻空间

随着城市建设的加速推进&#xff0c;施工过程中的环境问题日益受到关注。新型基坑气膜以其卓越的防尘、降噪、节能和防火功能&#xff0c;成为施工开挖领域中的得力干将&#xff0c;极大地提升了绿色施工的水平。 基坑气膜的作用 基坑气膜在施工现场形成了一个完全封闭的作业空…

JavaWeb系列七: 动态WEB开发核心(Servlet) 下

韩老师学生 ServletConfigServletContext网站计数器 HttpServletRequest细节1细节2细节3 Dispathcer请求转发应用实例请求转发细节和注意事项习题 HttpServletResponse请求重定向请求重定向注意事项动态获取到application context练习题 ServletConfig ●ServletConfig基本介绍…

1.文件上传漏洞渗透及防御(OWASP实战训练)

1.文件上传漏洞渗透及防御&#xff08;OWASP实战训练&#xff09; OWASPupload上传漏洞实验一&#xff1a;低安全模式下&#xff0c;上传任意类型的文件&#xff0c;文件大小不受限制实验二&#xff0c;安全级别调整将其变为中等安全级别实验三&#xff1a;将其设为高安全级别 …

【教程】如何一步一步训练一个SOM神经网络-自组织竞争神经网络(Self-organizing Feature Map)

本文来自《老饼讲解-BP神经网络》https://www.bbbdata.com/ 目录 一、什么是SOM神经网络1.1.SOM神经网络有什么用1.2.SOM神经网络是如何聚类的 二、如何训练一个SOM神经网络2.1. 训练一个SOM神经网络的代码示例2.2. 如何查看SOM神经网络的聚类中心 SOM神经网络全称为自组织竞争…

Redis-主从复制-测试主从模式下的读写操作

文章目录 1、在主机6379写入数据2、在从机6380上写数据报错3、从机只能读数据&#xff0c;不能写数据 1、在主机6379写入数据 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> set uname jim OK 127.0.0.1:6379> get uname "jim" 127.0.0.1:6379>…

rancher快照备份至S3

巧用rancher的S3快照备份功能&#xff0c;快速实现集群复制、集群转移、完全崩溃后的极限修复 1.进入集群管理&#xff0c;在对应的集群菜单后&#xff0c;点击编辑配置 2.选择ETCD&#xff0c;启用&#xff0c;Backup Snapshots to S3选项 并填入你的minio 3 配置成功后 手…

C# 信号量的使用

学习来源&#xff1a;《.net core 底层入门》 第六章第9节&#xff1a;信号量 案例&#xff1a;主线程负责添加数据&#xff0c;子线程负责获取数据 使用SemaphoreSlim&#xff08;轻信号量&#xff09;实现&#xff1a; using System; using System.Collections.Generic; us…

python中的<class ‘complex‘>

一般编程里面不怎么会讲&#xff0c;但是还是挺强大的一个类。 在 Python 中&#xff0c;<class complex> 表示复数类型。复数是一种包含实部和虚部的数学数&#xff0c;可以用 a bj 的形式表示&#xff0c;其中 a 表示实部&#xff0c;b 表示虚部&#xff0c;j 是虚数…

13 物理层介质及设备

物理层介质及设备 一、线缆的连接 &#xff08;一&#xff09;线序 ​ 线序&#xff1a; RJ-45连接头12345678568A绿白绿橙白蓝蓝白橙棕白棕568B橙白橙绿白蓝蓝白绿棕白棕 ​ 1、2发送&#xff0c;3、6接收 &#xff08;二&#xff09;线缆的应用 1.线缆的连接 ​ 标准…

Spring自定义标签体系和应用

我们知道&#xff0c;在使用Dubbo框架时&#xff0c;需要指定配置文件中的application、protocol、registry、provider、service等服务器端和客户端的配置项&#xff0c;典型的配置方法如下所示。通过这些配置项&#xff0c;我们可以基于Spring容器来启动Dubbo服务。 <!-- …

【2024.6.23】今日科技时事:科技前沿大事件

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

探索PHP中的函数

在PHP编程中&#xff0c;函数是一个非常重要的概念。函数可以帮助我们将代码组织成可重复使用的块&#xff0c;从而提高代码的可读性和可维护性。本文将介绍PHP中的函数&#xff0c;包括函数的定义、参数传递、返回值、内置函数和自定义函数等内容&#xff0c;帮助读者更好地理…

WPF 深入理解八、Binding 绑定

Binding 创建一个Demo 1 1.创建三个输入框&#xff0c;按钮 2.为按钮创建点击方法 3.点击按钮 三个输入框&#xff0c;分别更新了自己的内容。 上面的展示&#xff0c;是一个传统的模式&#xff0c;事件驱动程序&#xff0c;通过事件来变更UI控件元素的内容。 示例二 创建…

OS_虚拟机

2024.06.21&#xff1a;操作系统虚拟机学习笔记 第4节 虚拟机 4.1 虚拟机基本概念4.2 一型虚拟机管理程序4.3 二型虚拟机管理程序4.4 用户态与内核态 本节的主要内容就是来分辨两种不同的虚拟机管理程序 4.1 虚拟机基本概念 利用虚拟化技术&#xff0c;把一台物理机器虚拟成多…

2024年在WordPress中创建销售活动的入门级优惠券方法

2024年在WordPress中创建销售活动的入门级优惠券方法 今天我想和大家分享一些关于如何在WordPress网站上创建销售活动的经验。无论你是电商新手还是已经有一定经验的店主&#xff0c;优惠券都是吸引顾客、增加销量的有力工具。在这篇文章中&#xff0c;我将介绍三款适合初学者…

链轮简单认识一下

今天咱们聊的话题是——链轮&#xff0c;这个应用非常广泛的机械零件。 什么是链轮&#xff1f; 链轮是一种带有齿或尖刺的机械轮&#xff0c;用于与链条或皮带啮合&#xff0c;以促使“轮子”的旋转和运动。这种啮合可确保同步运动&#xff0c;使链轮和皮带能够高效地协同运行…

Linux-磁盘管理与文件系统

目录 一、磁盘结构 1、磁盘的物理结构 2、磁盘的数据结构 3、磁盘存储容量 4、接口类型 二、磁盘分区 1、磁盘的两种分区方式 1.1、MBR分区 1.2、GPT分区 三、查看硬盘的分区情况 1、Fdisk—查询磁盘设备 2、lsblk—以树形查看磁盘分区 3、blkid—查看磁盘的UUID …

Elasticsearch的快照

ES的快照是什么&#xff1f; snapshot是一个ES集群或者某个指定索引的备份&#xff0c;快照一般用在 不停机的状态下对ES集群进行备份当硬件故障时恢复集群数据用于跨集群的数据迁移对冷数据或冻结数据做快照以降低存储成本&#xff0c;依赖于可搜索的快照。-收费功能 一个快…