网站首页 > 资源文章 正文
深度优先搜索算法利用的是回溯算法思想。这个算法思想非常简单,但是应用却非常广泛。它除了用来指导像深度优先搜索这种经典的算法设计之外,还可以用在很多实际的软件开发场景中,比如正则表达式匹配、编译原理中的语法分析等。
除此之外,很多经典的数学问题都可以用回溯算法解决,比如数独、八皇后、0-1背包、图的着色、旅行商问题、全排列等等。既然应用如此广泛,我们今天就来学习一下这个算法思想,看看它是如何指导我们解决问题的。
笼统地讲,回溯算法很多时候都应用在“搜索”这类问题上。不过这里说的搜索,并不是狭义的指我们前面讲过的图的搜索算法,而是在一组可能的解中,搜索满足期望的解。
回溯的处理思想,有点类似枚举搜索。我们枚举所有的解,找到满足期望的解。为了有规律地枚举所有可能的解,避免遗漏和重复,我们把问题求解的过程分为多个阶段。每个阶段,我们都会面对一个岔路口,我们先随意选一条路走,当发现这条路走不通的时候(不符合期望的解),就回退到上一个岔路口,另选一种走法继续走。
经典的回溯例子——八皇后问题
我们有一个8x8的棋盘,希望往里放8个棋子(皇后),每个棋子所在的行、列、对角线都不能有另一个棋子。你可以看我画的图,第一幅图是满足条件的一种方法,第二幅图是不满足条件的。八皇后问题就是期望找到所有满足这种要求的放棋子方式。
我们把这个问题划分成8个阶段,依次将8个棋子放到第一行、第二行、第三行……第八行。在放置的过程中,我们不停地检查当前的方法,是否满足要求。如果满足,则跳到下一行继续放置棋子;如果不满足,那就再换一种方法,继续尝试。
回溯算法非常适合用递归代码实现
在实现的过程中,剪枝操作是提高回溯效率的一种技巧。利用剪枝,我们并不需要穷举搜索所有的情况,从而提高搜索效率。尽管回溯算法的原理非常简单,但是却可以解决很多问题,比如我们开头提到的深度优先搜索、八皇后、0-1背包问题、图的着色、旅行商问题、数独、全排列、正则表达式匹配等等。如果感兴趣的话,你可以自己搜索研究一下,最好还能用代码实现一下。如果这几个问题都能实现的话,你基本就掌握了回溯算法。
回溯法应用
当问题是要求满足某种性质(约束条件)的所有解或最优解时,往往使用回溯法。
它有“通用解题法”之美誉。
解决一个回溯问题,实际上就是一个决策树的遍历过程。你只需要思考 3 个问题:
1、路径:也就是已经做出的选择。
2、选择列表:也就是你当前可以做的选择。
3、结束条件:也就是到达决策树底层,无法再做选择的条件。
代码方面,回溯算法的框架:
result = []
func backtrack(路径, 选择列表){
if 满足结束条件{
result.add(路径)
return
}
for 选择 range 选择列表{
做选择
backtrack(路径, 选择列表)
撤销选择
}
}
1.0-1背包问题
0-1背包是非常经典的算法问题,很多场景都可以抽象成这个问题模型。这个问题的经典解法是动态规划,不过还有一种简单但没有那么高效的解法,那就是今天讲的回溯算法。动态规划的解法我下一节再讲,我们先来看下,如何用回溯法解决这个问题。
0-1背包问题有很多变体,我这里介绍一种比较基础的。我们有一个背包,背包总的承载重量是Wkg。现在我们有n个物品,每个物品的重量不等,并且不可分割。
我们现在期望选择几件物品,装载到背包中。在不超过背包所能装载重量的前提下,如何让背包中物品的总重量最大?
实际上,背包问题我们在贪心算法那一节,已经讲过一个了,不过那里讲的物品是可以分割的,我可以装某个物品的一部分到背包里面。今天讲的这个背包问题,物品是不可分割的,要么装要么不装,所以叫0-1背包问题。显然,这个问题已经无法通过贪心算法来解决了。我们现在来看看,用回溯算法如何来解决。
对于每个物品来说,都有两种选择,装进背包或者不装进背包。对于n个物品来说,总的装法就有2^n种,去掉总重量超过Wkg的,从剩下的装法中选择总重量最接近Wkg的。不过,我们如何才能不重复地穷举出这2^n种装法呢?
这里就可以用回溯的方法。我们可以把物品依次排列,整个问题就分解为了n个阶段,每个阶段对应一个物品怎么选择。先对第一个物品进行处理,选择装进去或者不装进去,然后再递归地处理剩下的物品。描述起来很费劲,我们直接看代码,反而会更加清晰一些。
package main
import (
"fmt"
)
var maxW int = 0
func main() {
var a = []int{1: 5, 2: 11, 3: 21, 4: 31, 5: 61, 7: 82, 9: 11, 12: 53}
F(0, 0, a, 10, 100)
fmt.Println(maxW)
}
//cw表示当前已经装进去的物品重量的和
//i表示考察到哪个物品了
//w背包的重量
//items表示物品的种类
//n表示物品个数
//假设背包可承受重量100,物品个数10,物品重量存储再数组a中
//F(0,0,a,10,100)
func F(i int, cw int, items []int, n int, w int) {
if cw == w || i == n { //cw==w表示已经装满,i==n表示考察完所有物品
if cw > maxW {
maxW = cw
}
return
}
F(i+1, cw, items, n, w)
if cw+items[i] <= w { //已经超过背包承受的重量时就不要再装了
F(i+1, cw+items[i], items, n, w)
}
}
- 上一篇: 算法|迷宫搜索之深搜DFS和广搜BFS
- 下一篇: 看完必会的回溯算法入门攻略,丈母娘看了都说好
猜你喜欢
- 2024-11-24 从电影《蝴蝶效应》中学习回溯算法的核心思想
- 2024-11-24 腾讯面试题目「回溯算法」排列问题
- 2024-11-24 力扣刷题技巧篇|程序员萌新如何高效刷题
- 2024-11-24 看完必会的回溯算法入门攻略,丈母娘看了都说好
- 2024-11-24 算法|迷宫搜索之深搜DFS和广搜BFS
- 2024-11-24 这一次,真正理解回溯算法
- 2024-11-24 leetcode 回溯法解题
- 2024-11-24 让人震惊的回溯算法解题套路框架你知道吗?
- 2024-11-24 高中数学学习(31)——排列组合(上)
- 2024-11-24 腾讯面试题目「回溯算法」排列问题(二)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- 电脑显示器花屏 (79)
- 403 forbidden (65)
- linux怎么查看系统版本 (54)
- 补码运算 (63)
- 缓存服务器 (61)
- 定时重启 (59)
- plsql developer (73)
- 对话框打开时命令无法执行 (61)
- excel数据透视表 (72)
- oracle认证 (56)
- 网页不能复制 (84)
- photoshop外挂滤镜 (58)
- 网页无法复制粘贴 (55)
- vmware workstation 7 1 3 (78)
- jdk 64位下载 (65)
- phpstudy 2013 (66)
- 卡通形象生成 (55)
- psd模板免费下载 (67)
- shift (58)
- localhost打不开 (58)
- 检测代理服务器设置 (55)
- frequency (66)
- indesign教程 (55)
- 运行命令大全 (61)
- ping exe (64)
本文暂时没有评论,来添加一个吧(●'◡'●)