回溯法是用来在解空间中寻找所有满足条件的解或者寻找最优解的非常有效的方法,其解空间的一种抽象表示就是一颗完全二叉树(假如读者连完全二叉树都不知道的话,就先去了解基本的数据结构吧。。。话说树这个数据结构真的是太强大了~~~)。回溯法计算的过程在二叉树中的抽象表示就是DFS(深度优先搜索),但是对于不同的问题,算法的框架略微有一点点的不同;笔者总结了一下,主要有一下两种:
框架1
void dfs(){
if(遍历到叶子节点){
if(结果满足条件){
打印结果;
return;
}else{
return;
}
}
for(;;){ //循环
if(条件){ // 条件检测可有可无,根据实际问题确定
......; // 进入其中一个子节点操作
dfs();
......; // 进入另一个子节点操作
}
}
}
框架2
void dfs(){
if(遍历到叶子节点){
if(结果满足条件){
打印结果;
return;
}else{
return;
}
}
if(条件1){ // 对于不同的问题,条件检测可有可无
......; //进入其中一个子节点操作
dfs();
......; //返回到父节点操作
}
if(条件2){ // 对于不同的问题,条件检测可有可无
......; //进入另一个子节点操作
dfs();
......; //返回父节点操作
}
}
对于可以用回溯法解决的问题,一般都会包含好多步骤,每个步骤有两种选择,特别是对于可以用框架1解决的问题,这种感觉特别明显;而对于可以采用框架2解决问题,更多的感觉到的是回溯,因为在框架2中,回溯到父节点是程序员自己处理的,而对于框架1,递归返回就代表了回溯;框架1的外层必须有个for循环。
还有一点不知道大家有没有发现,无论哪种框架,dfs中都不存在else语句,因为这不是一个二选一的逻辑,这是一个递归遍历树的逻辑,只有当遍历到叶节点时,才能验证该路径属于问题的解,此时递归结束,所以第一个if语句无论哪种框架都必须有。