回溯法是设计递归过程的一种重要方法,它的求解过程实质上一个先序遍历一颗“状态树”的过程,只是这个课树不是遍历前预先建立的,而是隐含在遍历过程中的。 ————严蔚敏版《数据结构》
回溯的过程就是在试探每一种可能,“能进则进,不能则退,退而求其他”。通过有序的试探,把每种可能的情况都遍历一遍。
说到回溯思想,那么我们不得不提“八皇后问题”,下面我们以八皇后问题,来展示回溯的思想。
在数据存储上,我们可以用一个二维list来表示A[][]皇后的位置,比如A[i][j]表示第i行第j列是皇后位置。但是考虑到条件限制:每一列(行)只能有一个皇后,所以其实可以用一个一维的list来存储,比如A[i]=j表示第i行第j列为皇后位置。因此按照回溯的思想,我们利用递归实现
#!/usr/bin/env python
import copy
def solveNQueens(n):
# 定义递归函数
def unit_queen(q_list, cur):
'''
q_list: 当前的list
cur: 当前皇后在的列
'''
if cur == n: # 所有行皇后互不冲突, 则将list添加到结果中
save_list = copy.deepcopy(q_list) # 注意此处得用深拷贝
all_queen.append(save_list)
return
# 遍历每一列
for col in range(0, n):
q_list[cur] = col # 第cur个(行)皇后在col列
flag = True
for row in range(0, cur):
# 两个(行)皇后在同一列 或者 两个(行)皇后在对角线
if q_list[row] == col or abs(q_list[row] - col) == cur - row:
flag = False
if flag:
unit_queen(q_list, cur + 1)
# 开始递归
all_queen = [] # 保存满足条件的list
queen_list = ['0'] * n # 初始化皇后list, 下标idx皇后对应矩阵中第idx行皇后
unit_queen(queen_list, 0) # 所以可能的情况
return all_queen
与其他经典思想的比较
- 相较于穷举法,它们都是对所有可能情况的遍历,但回溯是更有规律的尝试,所以尝试次数小于穷举
- 相较于贪心算法,它们都是根据当前的“处境”来选择下一步,但是贪心算法做最优的选择,回溯做随机(或者顺序)选择,而回溯可以在不满足条件的前提下选择退一步,重新选择。
- 相较于动态规划,它们都从某种角度上,保留了中间结果,避免重复计算(或尝试)。但动态规划是一个从局部最优找全局最优的过程,回溯则是把所有符合条件的可能都找出来。
更多内容,欢迎关注“机器爱学习”公众号~