目录:
- 算法框架
- 回溯法的定义
- 解题步骤
- 基本思想
- 经典例题
- 0-1背包问题
- 旅行售货员问题
- 装载问题
- 最大团问题
- 批处理作业调度
- n皇后问题
- 图的m着色问题
算法框架
回溯法的定义
回溯法是一个既带有系统性又带有跳跃性的搜索算法。
系统性指能够全面搜索;跳跃性则是可以有目的性地提前筛选掉不合格的解
因此回溯法有“通用的解题法”之称
解题步骤
- 首先要明确定义问题的解空间(一个问题所有解的集合)
- 确定易于搜索的解空间结构, 将解空间组织成树或图的形式
- 以深度优先方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索
剪枝函数可分为约束函数和限界函数
- 约束函数:在扩展结点处剪去不满足约束的子树
- 限界函数:剪去得不到最优解的子树
递归函数实现回溯法
代码框架【来自百度百科】
void BackTrace(int t){//第t层
if(t>n)//n为树的高度,此时t为叶子结点
Output(t);//输出结果
else{
for(int i=f(n,t);i<=g(n,t);i++){//f(n,t)为开始结点,g(n,t)为结束结点,遍历
x[i]=h(i);//记录可选值
if(Constraint(t)&&Bound(t))//限界函数
BackTrace(t+1)//满足限界函数,往下一层移动
}
}
}
回溯法的算法框架中的回溯是靠递归程序本身实现,而非我们敲代码解决回溯到上一层,此处需要了解递归的本质,递归的本质可以理解为后进先出的栈,这样我们就清楚为什么没有返回上一层的代码。此时,递归是实现回溯的工具
如果有更好理解回溯法中的回溯实现,期待和我交流!
迭代实现回溯法
代码框架【来自百度百科】
void IterativeBackTrace(void) {
int t = 1;//第一层开始
while(t>0) {//当t=0,整个解空间组织就没有可扩展结点
if(f(n, t) <= g( n, t))//当开始结点小于终止结点
for(int i = f(n, t); i <= g(n, t); i++ ) {//遍历结点
x[t] = h(i);//记录可选值
if(Constraint(t) && Bound(t)) {//限界函数
if ( Solution(t))//判断是否满足条件
Output(x);//输出结果
else
t++;//进行下一层的遍历
}
}
else t− −;//遍历完t层下一层的结点
}
}
基本思想
最关键的一步就是 如何在解空间的组织结构中找出最优解
了解了基本思想后,我们就知道了答案
确定解空间的组织结构后,回溯法从开始结点(根结点)出发,以深度优先方式搜索整个解空间。这个开始结点就成为活结点,同时也成为当前的可扩展结点。在当前可扩展结点处,搜索向纵深方向移至一个新的结点。如果在当前可扩展结点不能再向纵深方向移动,则可扩展结点成为死结点。回溯到最近的活结点处,并使这个活结点成为当前可扩展结点。由此方式搜索整个解空间直到找出所要求的解或解空间中已无活结点。
了解了基本思想后,让我们进入经典例题来切身感受回溯法的解题模式
回溯法经典例题(一)java解背包问题
回溯法经典例题(二)java解装载问题
回溯法经典例题(三):java解最大团问题MCP
回溯法经典例题(四):java解批处理作业调度
回溯法经典例题(五):java解n皇后问题
回溯法经典例题(六):java解图的m着色问题