算法设计与分析——回溯法

本文介绍了回溯法的概念,包括在解空间树上的搜索策略,解题步骤中的子集树和排列树结构,以及如何通过剪枝函数优化搜索。重点讨论了时间复杂度分析和经典应用示例,强调了确定解空间结构和有效剪枝的重要性。
摘要由CSDN通过智能技术生成

一.相关概念:

回溯法:定义在解空间树上搜索解的算法,具有剪枝函数的深度优先生成树
问题的解向量:一个问题的解能表示成一个n元组(x1,x2...xn),xi取0或1
显约束:对分量xi取值限定
隐约束:对满足问题的解,而对不同分支施加约束
解空间:满足显式约束条件的所有n元组的向量,构成该实例的一个解空间,组织成一颗树即解空间树.

注:同一问题可能有不同的空间树表示,表示越简单,解空间越小,搜索越快

扩展结点:一个正在产生儿子的结点
活结点:一个自身己生成,但其儿子还没有全部生成的结点

死结点:一个所有儿子已经产生的结点
在搜索过程中动态产生问题的解空间树,边搜索边扩展分支

注:数据结构中树深度优先遍历是先创建树,再深度优先通历。而回溯法在任何时刻只保留从根到当前扩展结点的路径,用一个数组X[]存储路径信息,所需空间复杂度O(h(n)),h(n)为叶结点路径长度

二.回溯法解题步骤:

1.针对问题描述,定义解空间

2.确定解空间结构

两类典型解空间树:①子集树/n叉树(左右分支性质不同,eg:0、1代表装或不装,因此剪枝函数适用于每个分支)

void backtrack(int t)
{
    if(t>n) output(x);
        else
            for(int i=0;i<=1;i++)//i分支取值0、1两种情况
            {
                x[t]=i;
                if(constraint(t)&&bound(t) backtrack(t+1));
            }
 }

②排列树(每个分支)

void backtrack(int t)
if(t>n) output(x);
    else
        for(int i=t;i<=n:i++)//i分支取值n种情况
        {
            swap(x[t],x[i]);//展开分支
            if(constraint(t)&&bound(t) backtrack(t+1));
            swap(x[i],x[t]);//返回过程
        }
}

3.以深度优先方式搜索解空间,搜索过程用剪枝函数避免无效搜索 <<避免无效搜索策略两类剪枝函数:①条件约束扩展结点(子树)剪去不满足约束条件子树②限界函数(在子树)剪去得不到最优解的分支>>

三.回溯法计算时间复杂度

(回溯法时间复杂度计算量往往非常高,只有理论意义,没有实际意义):

①计算出解空间树中除叶子层之外的结点总数f(n)

②每个非叶子节点扩展出其下层的所有分支的时间复杂度g(n)

③算法时间复杂度f(n)*g(n)

四.回溯法经典例题

五.回溯法总结

1)回溯法解决的问题,其解一定可以表示成n元组的形式。
(2)确定易于求解的解空间树。常用:子集树、排列树、n叉树等
一个问题有可能对应二种或多种解空间树,评价的标准:最后一层叶子结点的数量越少越好。
(3)剪枝函数的设计:要求在保证剪枝效率的情况下计算尽量简单。
对于子集树,通常左分支使用约束函数、右分支使用限界函数剪枝。对于排列树或n叉树,这两个函数同时应用于每个分支。
(4)回溯法是有套路的,一般在递归调用backtrack函数前、后的代码动作是相反的。
(5)到达叶子结点时,如果是求最优解,你要确定需不需要跟之前的最优解比较来更新最优解。有些情况是必须要经过比较确认后才能更新为当前最优解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值