回溯法
原文:https://my.oschina.net/u/3024426/blog/4689026
回溯法(Back Tracking Method)(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 “回溯点”。
可以把回溯法看成是递归调用的一种特殊形式。
代码方面,回溯算法的框架:
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。
总结就是:
循环 + 递归 = 回溯
引言
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就 “回溯” 返回,尝试别的路径。
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为 “回溯点”。
许多复杂的,规模较大的问题都可以使用回溯法,有 “通用解题方法” 的美称。
算法思想
回溯(backtracking) 是一种系统地搜索问题解答的方法。为了实现回溯,首先需要为问题定义一个解空间(solution space),这个空间必须至少包含问题的一个解(可能是最优的)。下一步是组织解空间以便它能被容易地搜索。典型的组织方法是图 (迷宫问题) 或树 (N 皇后问题)。一旦定义了解空间的组织方法,这个空间即可按深度优先的方法从开始节点进行搜索。
回溯方法的步骤如下:
- 定义一个解空间,它包含问题的解。
- 用适于搜索的方式组织该空间。
- 用深度优先法搜索该空间,利用限界函数避免移动到不可能产生解的子空间。
回溯算法的一个有趣的特性是在搜索执行的同时产生解空间。在搜索期间的任何时刻,仅保留从开始节点到当前节点的路径。因此,回溯算法的空间需求为 O(从开始节点起最长路径的长度)。这个特性非常重要,因为解空间的大小通常是最长路径长度的指数或阶乘。所以如果要存储全部解空间的话,再多的空间也不够用。


这段代码实现了经典的回溯算法来生成一个数组的所有排列。让我们逐步分析代码的执行过程,以确定最终的控制台输出。
- 初始化数组和结果列表:
int[] nums = { 1, 2, 3 };初始化一个包含三个元素的数组。List<List<int>> result = new List<List<int>>();初始化一个空的列表来存储所有的排列结果。
- 调用回溯函数:
Backtrack(nums, new List<int>(), result);从空列表开始调用回溯函数。
- 回溯函数的工作原理:
- 终止条件:如果
tempList.Count == nums.Length,即临时列表的长度等于原数组的长度,说明已经找到了一个完整的排列,将其添加到结果列表中。 - 选择:遍历数组
nums中的每个元素,如果当前元素不在tempList中,则将其添加到tempList中。 - 递归调用:对更新后的
tempList进行递归调用,继续构建排列。 - 撤销选择:递归调用返回后,移除最后添加的元素,以尝试其他可能的排列。
- 终止条件:如果
- 遍历结果列表并打印:
- 使用
foreach循环遍历结果列表result,并将每个排列转换为字符串格式输出。
- 使用
排列生成过程:
- 初始状态:
tempList = [] - 第一次选择:可以选择 1, 2, 或 3。
- 选择 1:
tempList = [1],递归。- 选择 2:
tempList = [1, 2],递归。- 选择 3:
tempList = [1, 2, 3],找到一个排列[1, 2, 3]。 - 撤销选择 3,
tempList = [1, 2]。
- 选择 3:
- 选择 3:
tempList = [1, 3],递归。- 选择 2:
tempList = [1, 3, 2],找到一个排列[1, 3, 2]。 - 撤销选择 2,
tempList = [1, 3]。
- 选择 2:
- 撤销选择 3,
tempList = [1]。
- 选择 2:
- 选择 2:
tempList = [2],递归。- 选择 1:
tempList = [2, 1],递归。- 选择 3:
tempList = [2, 1, 3],找到一个排列[2, 1, 3]。 - 撤销选择 3,
tempList = [2, 1]。
- 选择 3:
- 选择 3:
tempList = [2, 3],递归。- 选择 1:
tempList = [2, 3, 1],找到一个排列[2, 3, 1]。 - 撤销选择 1,
tempList = [2, 3]。
- 选择 1:
- 撤销选择 3,
tempList = [2]。
- 选择 1:
- 选择 3:
tempList = [3],递归。- 选择 1:
tempList = [3, 1],递归。- 选择 2:
tempList = [3, 1, 2],找到一个排列[3, 1, 2]。 - 撤销选择 2,
tempList = [3, 1]。
- 选择 2:
- 选择 2:
tempList = [3, 2],递归。- 选择 1:
tempList = [3, 2, 1],找到一个排列[3, 2, 1]。 - 撤销选择 1,
tempList = [3, 2]。
- 选择 1:
- 撤销选择 2,
tempList = [3]。
- 选择 1:
- 选择 1:
- 撤销选择 2,
tempList = []。 - 撤销选择 1,回到初始状态。
控制台输出:
| 1, 2, 3 | |
| 1, 3, 2 | |
| 2, 1, 3 | |
| 2, 3, 1 | |
| 3, 1, 2 | |
| 3, 2, 1 |

浙公网安备 33010602011771号