数据结构与算法(五)回溯算法(Java)

目录

    • 一、简介
      • 1.1 定义
      • 1.2 特性
      • 1.3 结点知识补充
      • 1.4 剪枝函数
      • 1.5 使用场景
      • 1.6 解空间
      • 1.7 实现模板
    • 二、经典示例
      • 2.1 0-1 背包问题
      • 2.2 N皇后问题

一、简介

1.1 定义

回溯法(back tracking)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回到上一步重新选择,这种走不通就退回再走的技术为 回溯法,而满足回溯条件时某个状态的点称为 “回溯点”

1.2 特性

回溯法是一个既带有 系统性 又带有 跳跃性 的搜索算法。

  • 系统性: 它在包含问题的所有解的解空间树中,按照 深度优先的策略,从根节点出发搜索解空间树。
  • 跳跃性: 算法搜索至解空间树的任一结点时,判断该结点为根的子树是否包含问题的解,如果肯定不包含,则跳过以该结点为根的子树的搜索,逐层向其始祖结点回溯。否则,进入该子树,继续深度优先的策略进行搜索。

这种以深度优先的方式系统地搜索问题解的算法称为回溯法,它 适用于解一些组合数较大的问题

1.3 结点知识补充

  • 扩展结点: 一个 正在生成儿子 的结点,称为扩展结点。
  • 活结点: 一个 自身已生成但其儿子还没有全部生成 的结点,称为活结点。
  • 死结点: 一个 所有儿子已经全部生成 的结点,称为死结点。

深度优先策略:

  • 如果对一个扩展结点 R,一旦生成了它的一个儿子 C,就把 C 当作新的扩展结点。
  • 在完成对子树 C(以 C 为根的子树)的穷尽搜索之后,将 R 重新变成扩展结点,继续生成 R 的下一个儿子(如果存在)。

广度优先策略:

  • 在一个扩展结点变成死结点之前,它一直是扩展结点。

回溯法:

  • 为了避免生成那些不可能产生最佳解的问题状态,要不断地利用 限界函数(bounding function)来处死那些实际上不可能产生所需解的活结点,以减少问题的计算量。
  • 具有剪枝函数的深度优先生成法称为回溯法。

那什么是限界函数呢?限界函数是剪枝函数的一种,下面我们一起来看下剪枝函数。

1.4 剪枝函数

剪枝函数:当某个顶点没有希望,则其所在的树枝可以减去。

剪枝函数一般有两种:

  • 约束函数: 剪去不满足约束条件的路径。
  • 限界函数: 减去不能得到最优解的路径。

1.5 使用场景

回溯就是递归的副产品,只要有递归就会有回溯。 其实回溯就是 递归搜索+剪枝,并不是什么高效的算法。

回溯算法的应用:

  • 当问题是要满足某种性质(约束条件)的所有接或最优解时,往往使用回溯法。

1.6 解空间

当确定回溯后,问题的关键转化为 如何定义问题的解空间,且转化为树结构,可以称之为 解空间树

解空间树分为:

  • 子集树: 当所给的问题是 从 n 个元素的集合中找到某种性质的子集 时,相应的解空间变为子集树。如:0-1 背包问题,从所给重量、价值不同的物品中挑选几个物品放入背包,使得在满足背包不超重的情况下,背包内物品价值最大。
  • 排列数: 所给的问题是确定 n 个元素满足某种性质的排列时,相应的解空间就是排列树。如:旅行问题,一个人把几个城市旅游一遍,要求走的路程最小,它的解法就是几个城市的排列。

1.7 实现模板

// 一定要分成横纵两个方面思考问题
public void backTracking(参数) {if (终止条件) {// 存放结果return;}// 注意 i=0,i=start 的区别for (选择:本层集合中元素(树中结点孩子的数量就是集合的大小)) {// 处理节点backTracking(路径,选择列表); // 递归,注意 i 和 i++ 的区别// 回溯,撤销处理结果}
}

二、经典示例

2.1 0-1 背包问题

题目:

有一个背包,容量由你自己输入,有n个物品,每个物品都具有容量与价值,这些都是由你自己输入的,请问,要怎么放物品到背包里,才能使得总价值最大呢,放入背包的总容量要小于等于背包的总容量。(如果一个物品放不下,则可以拆分成多个小块)
背包:M:100
物品:N:7
重量 价值
10 20
20 40
30 30
25 20
50 40
10 35
60 70

思路:

  • 迭代进行深度优先遍历;
  • 如果重量超出容量不予考虑;
  • 不超出容量情况下,获取价值最大值。

代码实现:

public static void main(String[] args) {int[][] items = new int[7][2];// 重量 价值items[0][0] = 10; items[0][1] = 20;items[1][0] = 20; items[1][1] = 40;items[2][0] = 30; items[2][1] = 30;items[3][0] = 25; items[3][1] = 20;items[4][0] = 50; items[4][1] = 40;items[5][0] = 10; items[5][1] = 35;items[6][0] = 60; items[6][1] = 70;int capacity = 100;System.out.println("背包的容量:" + capacity);StringBuilder builder = new StringBuilder();for (int[] item : items) {builder.append(Arrays.toString(item));}System.out.println(items.length + " 个物品的重量、价值:" + builder.toString());int maxValue = maxValue(items, capacity);System.out.println("最大价值:" + maxValue);
}private static int maxValue(int[][] items, int capacity) {// 0-未放入背包 1-放入背包int[] flag = new int[items.length];List<int[]> record = new ArrayList<>();int maxValue = maxValue(items, capacity, flag, 0, 0, record);for (int[] item : record) {capacity = capacity - item[0];System.out.println("重量为 " + item[0] + ",价值为 " + item[1] + " 的物品被放入背包,剩余容量:" + capacity);}return maxValue;
}private static int maxValue(int[][] items, int capacity, int[] flag, int weightSum, int oldMaxValue, List<int[]> record) {if (weightSum > capacity) {return -1;}int maxValue = oldMaxValue;for (int i = 0; i < items.length; i++) {if (flag[i] == 0) {flag[i] = 1;int tmpValue = maxValue(items, capacity, flag, weightSum + items[i][0], oldMaxValue + items[i][1], record);if (tmpValue != -1) {if (tmpValue > maxValue) {maxValue = tmpValue;record.clear();// 用于记录日志for (int j = 0; j < flag.length; j++) {if (flag[j] == 1) {record.add(items[j]);}}}}flag[i] = 0;}}return maxValue;
}

执行结果:

在这里插入图片描述

2.2 N皇后问题

N皇后

题目:

设计一种算法,打印 N 皇后在 N × N 棋盘上的各种摆法,其中每个皇后都不同行、不同列,也不在对角线上。这里的“对角线”指的是所有的对角线,不只是平分整个棋盘的那两条对角线。

注意:本题相对原题做了扩展

示例:

 输入:4输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]解释: 4 皇后问题存在如下两个不同的解法。
[[".Q..",  // 解法 1"...Q","Q...","..Q."],["..Q.",  // 解法 2"Q...","...Q",".Q.."]
]

代码实现:

public static void main(String[] args) {List<List<String>> result = solveNQueens(4);result.forEach(o -> {o.forEach(System.out::println);System.out.println("----");});
}public static List<List<String>> solveNQueens(int n) {List<List<String>> list = new ArrayList<>();handleQueens(n, 0, new int[n], new ArrayList<>(), new HashSet<>(), new HashSet<>(), list);return list;
}private static void handleQueens(int n, int level, int[] flag, List<String> queens, Set<Integer> diagonalSet, Set<Integer> reverseDiagonalSet, List<List<String>> list) {if (level >= n) {list.add(new ArrayList<>(queens));return;}for (int i = 0; i < n; i++) {int diagonal = i - level;int reverseDiagonal = i + level;if (flag[i] == 0 && !diagonalSet.contains(diagonal) && !reverseDiagonalSet.contains(reverseDiagonal)) {flag[i] = 1;queens.add(getLineStr(i, n));diagonalSet.add(diagonal);reverseDiagonalSet.add(reverseDiagonal);handleQueens(n, level + 1, flag, queens, diagonalSet, reverseDiagonalSet, list);reverseDiagonalSet.remove(reverseDiagonal);diagonalSet.remove(diagonal);queens.remove(queens.size() - 1);flag[i] = 0;}}
}private static String getLineStr(int i, int n) {StringBuilder builder = new StringBuilder();for (int j = 0; j < n; j++) {builder.append(j == i ? "Q" : ".");}return builder.toString();
}

执行结果:

在这里插入图片描述

整理完毕,完结撒花~ 🌻





参考地址:

1.回溯算法详细总结,https://zhuanlan.zhihu.com/p/165083789

2.回溯算法(BackTracing),https://zhuanlan.zhihu.com/p/495574746?utm_id=0

3.彻底搞懂回溯法(本文真的很详细),https://blog.csdn.net/m0_52824954/article/details/123467217

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

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

相关文章

Linux环境下的MySQL安装

文章目录 前提说明1.卸载内置环境2.检查系统安装包3.卸载这些默认安装包4.获取MySQL官方yum源5.安装MySQLyum源&#xff0c;对比前后yum源6.查看yum源是否生效7.安装MySQL服务8.查看相对应的配置文件9.启动服务10.查看启动服务11.登录方法一12.登录方法二13.登录方法三14.设置开…

两种做法——判断是否是二叉搜索树

https://leetcode.cn/problems/validate-binary-search-tree/description/?envTypestudy-plan-v2&envIdtop-interview-150 方法一&#xff1a;中序遍历 考虑只有两个节点和一个结点的情况&#xff0c;可以头尾各加一个最大最小值&#xff0c;不用特判了&#xff0c;也可…

谷达冠楠:现在做抖音电商到底怎么样

随着互联网的发展&#xff0c;电商行业也在不断地壮大。而近年来&#xff0c;抖音作为一款短视频社交平台&#xff0c;也逐渐成为了电商的新兴渠道。那么&#xff0c;现在做抖音电商到底怎么样呢? 首先&#xff0c;抖音拥有庞大的用户群体。根据数据显示&#xff0c;抖音的日活…

C++中单引号‘‘和双引号““的区别

操作系统&#xff1a;Windows 10 IDE&#xff1a;CLion 单引号&#xff1a;表示一个字符&#xff0c;例如 a 双引号""&#xff1a;表示一个字符串&#xff0c;例如 "a" 在C中&#xff0c;使用双引号可以方便地创建字符串&#xff0c;而使用单引号可以方便…

Python语言基础知识(一)

文章目录 1、Python内置对象介绍2、标识符与变量3、数据类型—数字4、数据类型—字符串与字节串5、数据类型—列表、元组、字典、集合6、运算符和表达式7、运算符和表达式—算术运算符8、运算符和表达式—关系运算符9.1、运算符和表达式— 成员测试运算符in9.2、运算符和表达式…

领先英伟达的GPU1.6倍性能,AMD发布最强AI芯片Instinct MI300

AMD发布最强AI芯片 Instinct MI300X AI 加速器和 Instinct MI300A 数据中心 APU&#xff0c;声称比 Nvidia 的竞争 GPU 领先 1.6 倍。与 Nvidia 竞争产品相比&#xff0c;在以下几个关键方面展示了显著优势&#xff1a;配置方面 内存容量&#xff1a;MI300X&#xff1a;拥有 1…

Linux---进程管理

本章主要介绍RHEL8中如何管理并查看进程。 了解进程并查看系统中存放的进程了解进程的信号进程优先级设置 进程介绍 在 Windows中打开任务管理器就可以查看到系统中的所有进程&#xff0c;如图下图所示。 这里列出了系统中所有的进程&#xff0c;不过也可以使用命令行工具来…

leetcode刷题:611.有效三角形的个数(双指针实现)

题目地址&#xff1a;有效三角形的个数 解决此题时&#xff0c;首先需要知道的是如何判断三个数字是否能够构成三角形。 我们知道&#xff0c;三角形任意两边之和都大于第三边。所以判断三个数字是否能构成三角形需要进行三次比较&#xff08;最基础的思路&#xff09; 方法一…

高精度加法,减法,乘法,除法(上)(C语言)

前言 加&#xff0c;减&#xff0c;乘&#xff0c;除这些运算我们自然信手捏来&#xff0c;就拿加法来说&#xff0c;我们要用c语言编程算ab的和&#xff0c;只需让sum ab即可&#xff0c;可是这是局限的&#xff0c;我们都知道int的表示的最大值为2147483647&#xff08;32位…

kepler.gl部署在线说明文档

1 概述 1.1 介绍 1、Kepler.gl 是一个强大的开源地理空间分析工具&#xff0c;用于大规模数据集的可视化。它由 Uber 的数据可视化团队开发&#xff0c;并且是基于 Web 技术构建的。Kepler.gl 涉及到以下几个主要技术领域&#xff1a; WebGL: Kepler.gl 通过 WebGL 进行渲染…

WVP-RPO开源项目搭建实践

0.拉取代码 GitHub - 648540858/wvp-GB28181-pro: WEB VIDEO PLATFORM是一个基于GB28181-2016标准实现的网络视频平台&#xff0c;支持NAT穿透&#xff0c;支持海康、大华、宇视等品牌的IPC、NVR、DVR接入。支持国标级联&#xff0c;支持rtsp/rtmp等视频流转发到国标平台&…

解锁全球潜力:IT外包解决跨国企业海外分支的IT需求

在全球化的浪潮中&#xff0c;跨国企业为了拓展业务辐射面&#xff0c;经常在世界各地设立海外分支。然而&#xff0c;这些分支机构面临着独特的挑战&#xff0c;其中包括解决复杂的IT需求。为了更高效地应对这些挑战&#xff0c;越来越多的企业正在转向IT外包&#xff0c;以便…

sqlserver已经启动了允许远程连接,但局域网内无法访问

sqlserver已经启动了允许远程连接&#xff0c;但局域网内无法访问。 可以确认一下sqlserver browser是不是没有启动。 修改启动模式为自动试一试。

【java】Java程序员,你掌握了多线程吗?

摘要&#xff1a;互联网的每一个角落&#xff0c;无论是大型电商平台的秒杀活动&#xff0c;社交平台的实时消息推送&#xff0c;还是在线视频平台的流量洪峰&#xff0c;背后都离不开多线程技术的支持。在数字化转型的过程中&#xff0c;高并发、高性能是衡量系统性能的核心指…

科技云报道:DDR5火了!揭开下一代超高速内存的秘密

科技云报道原创。 在最新的存储市场动态中&#xff0c;存储芯片大厂的减产策略显现出其效果&#xff0c;特别是在DDR内存领域。 根据台湾工商时报的最新报道&#xff0c;第四季度的内存芯片合约价格出现了超出预期的上涨。 这一价格变动尤其在DDR5芯片上表现突出&#xff0c…

使用Redis构建简易社交网站(2)-处理用户关系

目的 本文目的&#xff1a;实现用户关注和取消关注功能。&#xff08;完整代码附在文章末尾&#xff09; 相关知识 在我之前的文章 《使用Redis构建简易社交网站(1)-创建用户与动态界面》中提到了如何实现简易社交网站中创建新用户和创建新动态功能。 那这篇文章将教会你掌…

第二证券:政策稳预期强信心 民间投资结构性亮点纷呈

民营经济是中国特色社会主义商场经济的重要组成部分&#xff0c;是推动中国式现代化和高质量展开的生力军。本年以来&#xff0c;国内外环境仍然复杂多变&#xff0c;我国民营企业展开耐性不减。受访专家标明&#xff0c;跟着支撑民营经济展开的系列严峻抉择计划安置执行落地&a…

js vue 输入正确手机号/邮箱后,激活“发送验证码”按钮

按钮禁止点击状态&#xff1a; 按钮能够点击状态&#xff1a; 我采用的方式是监听手机号/邮箱输入框的输入事件&#xff0c;即实判断用户输入的数据是否满足规则&#xff0c;如果满足手机号/邮箱规则&#xff0c;则激活“获取验证码”按钮。 话不多说&#xff0c;上代码 样式…

pWnOS v2.0

该靶机绑定了静态IP地址 10.10.10.100&#xff0c;所以这里需要修改我们的网络配置&#xff01;整个网段修改为10.10.10.0/24 信息收集 主机存活探测 arp-scan -l 端口信息探测 nmap -sT --min-rate 10000 -p- 10.10.10.100 &#xff08;只开放了22 80端口&#xff09; 服务…

运行时更改Android应用程序图标

设想一下&#xff0c;当我们正在开发一款应用。随着某个节日的临近&#xff0c;我们可能希望通过更改应用图标来增强用户的节日氛围&#xff0c;例如在图标上添“新年特惠”或者“龙年大吉”等标签。 这种小小的改变看似不经意&#xff0c;却能够吸引用户的注意。 运行时更改应…