你的打赏是我奋笔疾书的动力!
按照我的惯例还是先把实例放出来撕咬一番。
例1:n皇后问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行、同一列、同一斜线45度上的皇后都会自动攻击)。
例如4皇后:
说明:图展示了4个皇后依次选择列号放置的不考虑约束条件的所有可能(也叫搜索空间),节点代表皇后,有4层代表了有4个皇后,分支代表该皇后可选择放置的列号(1,2,3,4), 我们在这些可能中搜索可行(满足约束条件的)解。我们可以推广到在n皇后的n叉树中搜索其可行解。解是其中一条从根节点到叶节点的路径。
例2 0-1背包问题。此问题有动态规划的解法。
有四件物品,价格V={12,11,9,8},重量W={8,6,4,3},背包载重B=13,求最大价值。
2个可行解:<0,1,1,1,>,选入物品2,3,4,价值28,重量13;<1,0,1,0>,选入物品1,3,价值21,重量12;最优解<0,1,1,1,>。图解如下:
说明 :图展示了4个物品依次分别决策是否装入背包的所有可能(也叫搜索空间),节点代表物品,有4层代表了有4个物品,分支代表该物品是否装入(0,1),我们在这些可能中搜索可行(满足约束条件的)解从而找出最优解。当然此物品也可以推广到n。
例3 所有货郎回路的遍历,找到最短回路。条件是城市之间两两联通。下图是4个城市的所有回路的可能排列:
说明:货郎选最短回路问题其实是一个排列的问题,可以运用数学中排列组合知识求得所有排列,然后逐一暴力搜索, 但如果排列得当,有章法可寻,那么搜索起解来可以说是得心用手。例如图中展示的排列,节点代表了排列中的城市,分支代表了选择城市,该节点有几个分支就代表了从该城市出发还可以选择几个未经过的城市,发现第三次选择之后就只剩下唯一的选择,因为总共有4个城市嘛,选4次之后没得选。解是其中一条从根节点到叶节点的路径。
以上三种问题分析的总结:
可以看到以上的问题都是在所有可能的排列组合的解里搜索可行解或者最优解,而且所有可能组合起来是树型的结构,我们知道,无论是数组,链表,还是树,都可看做图,那么图的搜索方式同样适用于树了,即图的深广遍历也适用于树。所谓的跳跃式遍历就是在深广遍历的基础上约束一些搜索条件,从而把不满足条件的节点以及以该节点为根的子树越过不考虑遍历。后面我们会看到并不是所有的树都可以跳跃式遍历,只有满足多米诺性质的树才可以跳跃式遍历。
深广优先遍历复习举例:从1开始
深度优先有:1-2-3-5-8-9-6-7-4,广度优先有:1-2-3-4-5-6-7-8-9
发现没有?竟然还没提到回溯!!!回溯到底是什么?操了,我看了一大半,还没看到回溯,是有点生气哦。
我们先感性认识一下回溯,其实那个跳跃式遍历就是回溯遍历!!!回溯首先有一点是它适用于搜索问题,其次回溯字面解释就是逆流而上。当我们组织好问题的所有可能的排列组合后,解就是其中的一些排列组合,我们开始从这些可能中搜索其解,搜索往往使用的是深广搜索技术,当碰到不满足条件的节点后,跳跃回退到父节点继续搜索下一个子节点,等等。下面我们真正和回溯算法打一下招呼。
回溯算法的基本内容
节点状态的举例:假设对下里的树使用深度优先遍历,从1节点开始,并假设目前访问到8节点上
访问次序:1-2-3-5-8,则根据状态分类节点,已完成:2,8,已访问但未结束:1,3,5,尚未访问:9,6,7,4
回溯算法的适用条件---多米诺性质
假设解向量是n维的,则下面的k满足:0 等价的逆否命题:P(x1,x2,x3,…,xk)不是解的部分向量则推得P(x1,x2,x3,…,xk+1)一定不为解的部分向量P(x1,x2,x3,…,xk)不是解的部分向量的时候才可以回溯搜索 举一个不满足多米诺性质的例子: 求不等式的解:5x1+4x2-x3<=10,1<=xk<=3,k=1,2,3 设解的部分向量P(x1,…,xk),P(x1,x2,x3)可以推得P(x1,x2)吗?即5x1+4x2-x3<=10可以推得5x1+4x2<=10吗?在1<=xk<=3的条件下(最起码都大于0),显然不成立。所以不满足多米诺性质,回溯搜索也就不可以运用了。 然而,我们令x3=3-x33,则5x1+4x2+x33 <=13,1<=xk<=3,k=1,2,0<=x3<=2此时,P(x1,x2,x33)却可以推得P(x1,x2),所以变换变量有了合适的约束条件可以使的满足多米诺性质。 回溯算法的设计步骤: 算法实现:分递归实现和迭代实现 递归实现: BackTrace(k) ReBackTrace(n) 迭代实现: BackTrace(k) 算法中的变量注释: Sk:解向量的第k个分量的选取值集合,例如:N皇后中的S1={1,2,3,4}表示该皇后四列都可以放置,当x1选第1列放置时,S2={3,4},x2选第3列放置时,S3=null,也就是此后皇后已经无处安放;0-1背包中S1={0,1}表示第一件物品可以选择装入或者不装入;货郎选路中S1={1,2,3,4}表示货郎选择哪一个城市出发都可以,S2={2,3,4}表示选择从1出发后只能选择走向2,3,4这3个中的一个城市。 k:解向量的分量的序号,分量的取值选取值集合Sk的序号,也是递归中递归的深度的序号 例4:图的着色问题。无相连通图G= 解:如下图: 搜索结构:m(=3)叉树 解向量: 约束条件:在 图解该问题的部分着色过程如下: 例5:九(奇数)宫格。(为了解决数独的算法而引入的一个问题) 填数的一个经典算法:1.把1填入第一行的中间一格;2.然后依次把后面的数字填入前面一个数字的右上格,若右上格是空的,则填入,若右上格有数,则填入当前位置的下面。 代码见我的github 例6:八皇后问题。代码见github,代码中有回溯思想的注释。 例7:数独。 搜索结构:m(=9)叉树 解向量: 约束条件:在 搜索结构如下图,绿色分支表示该数字(符合约束条件行得通)可以填入小格子内,红色分支表示该数字不符合约束条件(行不通),小蓝点表示解向量中的分量或者未填数字的小格子,在相同层的小蓝点表示同一个分量或同一个未填数字的小格子: 上图中9叉树的层数等于数独中未填数字的小个子的个数,其中在图中我们发现使用约束条件来约束数字的填写之后,图中红色分支显得格外多,从树根至树叶的绿色路径中的节点的层数如果不等于数独中未填数字的小个子的个数,则此路径一定存在着回溯,具体算法见我的github. 例 8 走迷宫 题目:3代表围墙,0代表通路,给出起始坐标(1,1),终点坐标(6,16),寻找起点到终点的通路。 搜索结构:m(=4)叉树,上、下、左、右4个方向 解向量:<(x1,y1),……,(xk,yj),……,(xm,yn)>,且xk ε [0-7],yj ε [0-17] 约束条件:走到<(x1,y1),……,(xk,yj)>处,若接下来的4个方向都没有到终点的通路,则要回溯至(xk,yj)点处,找另一个方向上到终点的通路 搜素图可参考数独的搜索图画出,代码见我的github。 支付宝打赏: 微信打赏:
null do
null do //满足约束的分支
你的打赏是我奋笔疾书的动力!