2020年7月17日ICPC训练联盟——递归与回溯
递归:
程序调用自身的编程技巧叫做递归,是子程序再起定义或说明中直接或间接调用自身的一种方法
简称:我调用我自己
视觉形式:德罗斯特效应
德罗斯特效应(Droste effect)是递归的一种视觉形式,是指一张图片的某个部分与整张图片相同,如此产生无限循环。
递归就是将一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解因此只需要少量的程序代码就可以描述出解题过程中需要的多次重复计算,使程序更加简洁清晰
递归算法一般用于解决三类问题:
1、函数定义是递归的(斐波那契数列、阶乘)
2、数据结构形式按照递归定义(二叉树的三种遍历、图的DFS)
3、问题的解法是递归的(回溯)
举个阶乘的例子,代码块如下:
int fac(int n) {
if (n == 1)//1!=1
return 1;
else
return n * fac(n - 1);//n!=n*(n-1)!
}
可以这样理解,我们假设n是3,这个函数该如何计算3!呢?
int fac(3) {//最终值是3*2*1
if (n == 1)//3!不等于1,不执行
return 1;
else//n就是3,等待fac(n-1)的值,fac(n-1)的值是2*1
return n * {int fac(3-1) {
if (n == 1)//2!不等于1
return 1;
else//n=2,算出来结果是2*1
return n *
{int fac(2-1) {
if (n == 1)//1!=1,执行
return 1;
}
}
}
};
}
采用递归方法求解回溯问题,是递归算法的一个应用。
回溯:
回溯法从初始状态出发,运用题目给出的条件、规则,按照纵深搜索的顺序
递归扩展所有可能情况,从中找出满足题意的解答。所以,回溯法就是走不通就退回再走的技术,非常适合用递归方法
回溯法是搜索算法中的一种控制策略,该算法从初始状态出发,
运用题目给出的条件、规则,按选优条件向前搜索,以达到目标。
当搜索到某一步时,发现原先选择并不优,或者达不到目标,就
退回一步重新选择。
这种方法与第四篇中图的深度优先搜索( DFS )在本质上是一致的。
在使用回溯法解题时,一般需要结合题意考虑如下因素:
• 【 1 】定义状态:即如何描述问题求解过程中每一步的状况。为了精简程序,
增加可读性,我们一般将参与子状态扩展运算的变量组合成当前状态列入
值参或局部变量,以便回溯时能恢复递归前的状态,重新计算下一条路径。
若这些参数的存储量大(例如数组),为避免内存溢出,则必须将其设为
全局变量,且回溯前需恢复其递归前的值。
• 【 2 】边界条件:即在什么情况下,程序不再递归下去。如果是求满足某个
特定条件的一条最佳路径,则当前状态到达边界时并非一定意味着此时就
是最佳目标状态,因此还须增加判别最优目标状态的条件。
• 【 3 】搜索范围:若当前子状态不满足边界条件,则扩展子状态。在这种情
况下,应如何设计扩展子状态的算符值范围。换句话说,如何设定 for 语句
中循环变量的初值和终值。
• 【 4 】约束条件和最优性要求:扩展出的子状态应满足什么条件方可继续
递归下去;如果是求满足某个特定条件的一条最佳路径,那么在扩展出某
子状态后是否继续递归搜索下去,不仅取决于子状态是否满足约束条件,
而且还取决于子状态是否满足最优性要求。
递归与回溯的综述:递归是一种算法结构。递归出现在程序的子程序中,形式上表现
为直接或间接的自己调用自己。而回溯则是一种算法思想,他是以递归实现的。回溯类似穷举法,但回溯有
“剪枝”功能,即自我判断过程