回溯法
回溯法有“通用的解题法”之称。用它可以系统地搜索一个问题的所有解或任一解。解空间树有子集树和排列树两种。具有剪枝函数的以深度优先方式系统搜索问题解的算法,它适用于解组合数较大的问题。
基本思想
具有剪枝函数的以深度优先方式系统搜索问题解的算法称为回溯法。
回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
回溯法搜索解空间树时,通常采用两种策略避免无效搜索,提高回溯法的搜索效率。其一是用约束函数在扩展结点处剪去不满足约束的子树;其二是用限界函数剪去得不到最优解的子树。这两类函数统称为剪枝函数。
基本步骤
在解该类问题时,首先要确定解向量和解空间树,然后以深度优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。
PS:解空间树只是一个概念上的树,并不是实际构建一棵树。在搜索过程中动态产生问题的解空间。
下面是算法框架:
子集树
void backtrack (int t) { if (t>n) output(x); else { for (int i=0;i<=1;i++) { x[t]=i; if (constraint(t) && bound(t)) backtrack(t+1); } } }
遍历子集树需O(2n)计算时间
排列树
void backtrack (int t) { if (t>n) output(x); else { for (int i=t;i<=n;i++) { swap(x[t], x[i]); if (constraint(t) && bound(t)) backtrack(t+1); swap(x[t], x[i]); } } }
遍历排列树需要O(n!)计算时间
复杂性分析
用回溯法解题的一个显著特征是在搜索过程中动态产生问题的解空间。在任何时刻,算法只保存从根结点到当前扩展结点的路径。如果解空间树中从根结点到叶结点的最长路径的长度为h(n),则回溯法所需的计算空间通常为O(h(n))。而显式地存储整个解空间则需要O(2h(n))或O(h(n)!)内存空间。