算法导读:
回溯法(back tracking)(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
白话:回溯法可以理解为通过选择不同的岔路口寻找目的地,一个岔路口一个岔路口的去尝试找到目的地。如果走错了路,继续返回来找到岔路口的另一条路,直到找到目的地。
根据定义来看,要实现回溯,需要两点1搜索,2解空间
解空间就是形如数组的一个向量[a1,a2,…,an]。这个向量的每个元素都是问题的部分解,只有当这个数组的每一个元素都填满(得到全部解)的时候,才表明这个问题得到了解答。因此几乎所有回溯的问题的难度都在于如何定义解空间。
下面的模板适用于所有"解空间确定"的回溯法的问题!!!
def backtrack(i, n, *args)
if condition:
add_answer()
else:
change()
backtrack(i+1, n, *args);
remove_change()
下面通过具体题目进一步感受回溯算法解空间
题目一
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 ‘Q’ 和 ‘.’ 分别代表了皇后和空位。
下面是回溯核心代码:
def backtrack(row):
for col in range(len(cb)):
if judge(row, col):
#开始试探
place_queen(row, col)
if row == len(cb) - 1:
add_cb()
else:
backtrack(row + 1)
#回到原点
remove_queen(row, col)
题目二
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
def backtrack(start):
for end in range(start, len(s)):
if judge(s[start:end + 1]):
temp.append(s[start:end+1])
if end + 1 == len(s):
save = copy.deepcopy(temp)
ans.append(save)
else:
backtrack(end + 1)
temp.pop()
题目三
累加数是一个字符串,组成它的数字可以形成累加序列。
一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。
给定一个只包含数字 ‘0’-‘9’ 的字符串,编写一个算法来判断给定输入是否是累加数。
说明: 累加序列里的数不会以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
#初始三个数通过for循环获取,这里只摘取回溯部分
def backtrack(num1, num2, num3, tot):
if judge(num1, num2, num3):
if tot + 1 == len(num):
self.ans = True
else:
for tot1 in range(tot + 1, len(num)):
if num[tot + 1] == '0' and tot + 1 != tot1:
continue
backtrack(num2, num3, int(num[tot + 1: tot1 + 1]), tot1)