520 likes | 784 Views
第 8 章 回溯法. 20090508. Brute Force 蛮力法. 扫描技术 —— 采用一定的策略奖待求解问题的所有元素依次处理一次,从而找出问题的解。. 子集. 总价值. 序号. 子集. 1. φ. 0. 0. 9. {2,3}. 7. 52. 2. {1}. 7. 42. 10. {2,4}. 8. 37. 3. {2}. 3. 12. 11. {3,4}. 9. 65. 4. {3}. 4. 40. 12. {1,2,3}. 14. 5. {4}. 5. 25. 13.
E N D
第8章 回溯法 20090508
Brute Force蛮力法 • 扫描技术——采用一定的策略奖待求解问题的所有元素依次处理一次,从而找出问题的解。
子集 总价值 序号 子集 1 φ 0 0 9 {2,3} 7 52 2 {1} 7 42 10 {2,4} 8 37 3 {2} 3 12 11 {3,4} 9 65 4 {3} 4 40 12 {1,2,3} 14 5 {4} 5 25 13 {1,2,4} 15 6 {1,2} 10 54 14 {1,3,4} 16 7 {1,3} 11 15 {2,3,4} 12 8 {1,4} 12 16 {1,2,3,4} 19 w1=7 v1=42 w4=5 v4=25 10 w3=4 v3=40 w2=3 v2=12 背包 物品1 物品2 物品3 物品4 序号 总重量 总重量 总价值 不可行 不可行 不可行 不可行 不可行 不可行 不可行
第8章 回溯法 8.1 概 述 8.2 图问题中的回溯法 8.3 组合问题中的回溯法 8.4 实验项目
8.1 概 述 8.1.1 问题的解空间 8.1.2 解空间树的动态搜索(1) 8.1.3 回溯法的求解过程 8.1.4 回溯法的时间性能
8.1.1 问题的解空间 复杂问题常常有很多的可能解,这些可能解构成了问题的解空间。解空间也就是进行穷举的搜索空间,所以,解空间中应该包括所有的可能解。确定正确的解空间很重要,如果没有确定正确的解空间就开始搜索,可能会增加很多重复解,或者根本就搜索不到正确的解。
例如:桌子上有6根火柴棒,要求以这6根火柴棒为边搭建4个等边三角形。例如:桌子上有6根火柴棒,要求以这6根火柴棒为边搭建4个等边三角形。 (b) 三维搜索空间的解 (a) 二维搜索空间无解 图8.1 错误的解空间将不能搜索到正确答案
对于有n个物品的0/1背包问题,其可能解的表示方式可以有以下两种:对于有n个物品的0/1背包问题,其可能解的表示方式可以有以下两种: (1)可能解由一个不等长向量组成,当物品i(1≤i≤n)装入背包时,解向量中包含分量i,否则,解向量中不包含分量i,当n=3时,其解空间是: { ( ), (1), (2), (3), (1, 2), (1, 3), (2, 3), (1, 2, 3) } (2)可能解由一个等长向量{x1, x2, …, xn}组成,其中xi=1(1≤i≤n)表示物品i装入背包,xi=0表示物品i没有装入背包,当n=3时,其解空间是: {(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (1, 1, 1) }
为了用回溯法求解一个具有n个输入的问题,一般情况下,将其可能解表示为满足某个约束条件的等长向量X=(x1, x2, …, xn),其中分量xi (1≤i≤n)的取值范围是某个有限集合Si={ai1, ai2, …, airi},所有可能的解向量构成了问题的解空间。
问题的解空间一般用解空间树(Solution Space Trees,也称状态空间树)的方式组织,树的根结点位于第1层,表示搜索的初始状态,第2层的结点表示对解向量的第一个分量做出选择后到达的状态,第1层到第2层的边上标出对第一个分量选择的结果,依此类推,从树的根结点到叶子结点的路径就构成了解空间的一个可能解。
1 1 0 对物品1的选择 9 2 1 0 1 0 对物品2的选择 6 3 10 3 0 1 1 0 0 0 1 1 对物品3的选择 4 7 11 8 5 14 15 12 对于n=3的0/1背包问题,其解空间树如图8.2所示,树中的8个叶子结点分别代表该问题的8个可能解。
1 1 4 2 3 2 18 34 24 2 3 4 3 1 4 2 1 4 2 1 3 13 19 29 35 3 50 55 60 8 24 45 40 3 1 2 3 2 3 4 4 2 1 1 2 1 1 4 1 4 2 4 3 3 4 4 2 3 3 9 16 22 32 36 38 51 53 56 58 61 63 6 11 14 20 25 27 30 41 46 48 4 43 4 4 3 4 1 4 3 2 1 4 2 4 2 3 1 1 3 2 2 1 3 3 2 1 10 17 23 33 37 39 52 54 57 59 62 64 7 12 15 21 26 28 31 42 47 49 5 44 图8.3 n=4的TSP问题的解空间树 对于n=4的TSP问题,其解空间树如图8.3所示,树中的24个叶子结点分别代表该问题的24个可能解,例如结点5代表一个可能解,路径为1→2→3→4→1,长度为各边代价之和。
8.1.2 解空间树的动态搜索(1) 回溯法从根结点出发,按照深度优先策略遍历解空间树,搜索满足约束条件的解。在搜索至树中任一结点时,先判断该结点对应的部分解是否满足约束条件,或者是否超出目标函数的界,也就是判断该结点是否包含问题的(最优)解,如果肯定不包含,则跳过对以该结点为根的子树的搜索,即所谓剪枝(Pruning);否则,进入以该结点为根的子树,继续按照深度优先策略搜索。
1 0 1 9 2 1 1 0 0 10 6 13 1 0 0 0 1 1 11 8 14 15 12 不可行解 价值=55 价值=30 价值=25 价值=20 价值=0 例如,对于n=3的0/1背包问题,三个物品的重量为{20, 15, 10},价值为{20, 30, 25},背包容量为25,从图8.2所示的解空间树的根结点开始搜索,搜索过程如下: 不可行解
回溯法的搜索过程涉及的结点(称为搜索空间)只是整个解空间树的一部分,在搜索过程中,通常采用两种策略避免无效搜索:回溯法的搜索过程涉及的结点(称为搜索空间)只是整个解空间树的一部分,在搜索过程中,通常采用两种策略避免无效搜索: (1)用约束条件剪去得不到可行解的子树; (2)用目标函数剪去得不到最优解的子树。 这两类函数统称为剪枝函数(Pruning Function)。 • 需要注意的是,问题的解空间树是虚拟的,并不需要在算法运行时构造一棵真正的树结构,只需要存储从根结点到当前结点的路径。
8.1.3 回溯法的求解过程 由于问题的解向量X=(x1, x2, …, xn)中的每个分量xi(1≤i≤n)都属于一个有限集合Si={ai1, ai2, …, airi},因此,回溯法可以按某种顺序(例如字典序)依次考察笛卡儿积S1×S2×…×Sn中的元素。 初始时,令解向量X为空,然后,从根结点出发,选择S1的第一个元素作为解向量X的第一个分量,即x1= a11,如果X=(x1)是问题的部分解,则继续扩展解向量X,选择S2的第一个元素作为解向量X的第2个分量,否则,选择S1的下一个元素作为解向量X的第一个分量,即x1= a12。依此类推,一般情况下,如果X=(x1, x2, …, xi)是问题的部分解,则选择Si+1的第一个元素作为解向量X的第i+1个分量时,有下面三种情况:
(1)如果X=(x1, x2, …, xi+1)是问题的最终解,则输出这个解。如果问题只希望得到一个解,则结束搜索,否则继续搜索其他解; (2)如果X=(x1, x2, …, xi+1)是问题的部分解,则继续构造解向量的下一个分量; (3)如果X=(x1, x2, …, xi+1)既不是问题的部分解也不是问题的最终解,则存在下面两种情况: ① 如果xi+1= ai+1k不是集合Si+1的最后一个元素,则令xi+1= ai+1k+1,即选择Si+1的下一个元素作为解向量X的第i+1个分量; ② 如果xi+1= ai+1k是集合Si+1的最后一个元素,就回溯到X=(x1, x2, …, xi),选择Si的下一个元素作为解向量X的第i个分量,假设xi= aik,如果aik不是集合Si的最后一个元素,则令xi= aik+1;否则,就继续回溯到X=(x1, x2, …, xi-1);
回溯法的一般框架——递归形式 advance(int k) 1. 对每一个x∈Sk循环执行下列操作 1.1 xk=x; 1.2 将xk加入X; 1.3 if (X是最终解) flag=true; return; 1.4 else if (X是部分解) advance(k+1);, 主算法 1.X={ }; 2. flag=false; 3. advance(1); 4. if (flag) 输出解X; else输出“无解”; 回溯法的递归形式的一般框架如下:
回溯算法的非递归迭代形式的一般框架如下: 回溯法的一般框架——迭代形式 1.X={ }; 2.flag=false; 3.k=1; 4.while (k>=1) 4.1 当(Sk没有被穷举)循环执行下列操作 4.1.1 xk=Sk中的下一个元素; 4.1.2 将xk加入X; 4.1.3 if (X为最终解) flag=true; 转步骤5; 4.1.4 else if (X为部分解) k=k+1; 转步骤4; 4.2 重置Sk,使得下一个元素排在第1位; 4.3 k=k-1; //回溯 5.if flag 输出解X; else 输出“无解”;
8.1.4 回溯法的时间性能 一般情况下,在问题的解向量X=(x1, x2, …, xn)中,分量xi (1≤i≤n)的取值范围为某个有限集合Si={ai1, ai2, …, airi},因此,问题的解空间由笛卡儿积A=S1×S2×…×Sn构成,并且第1层的根结点有|S1|棵子树,则第2层共有|S1|个结点,第2层的每个结点有|S2|棵子树,则第3层共有|S1|×|S2|个结点,依此类推,第n+1层共有|S1|×|S2|×…×|Sn|个结点,他们都是叶子结点,代表问题的所有可能解。
在用回溯法求解问题时,常常遇到两种典型的解空间树: (1)子集树(Subset Trees):当所给问题是从n个元素的集合中找出满足某种性质的子集时,相应的解空间树称为子集树。在子集树中,|S1|=|S2|=…=|Sn|=c,即每个结点有相同数目的子树,通常情况下c=2,所以,子集树中共有2^n个叶子结点,因此,遍历子集树需要Ω(2n)时间。(2)排列树(Permutation Trees):当所给问题是确定n个元素满足某种性质的排列时,相应的解空间树称为排列树。在排列树中,通常情况下,|S1|=n,|S2|=n-1,…,|Sn|=1,所以,排列树中共有n!个叶子结点,因此,遍历排列树需要Ω(n!)时间。
8.2 图问题中的回溯法 8.2.1 图着色问题 8.2.2 哈密顿回路问题
8.2.1 图着色问题 图着色问题描述为:给定无向连通图G=(V, E)和正整数m,求最小的整数m,使得用m种颜色对G中的顶点着色,使得任意两个相邻顶点着色不同。
由于用m种颜色为无向图G=(V, E)着色,其中,V的顶点个数为n,可以用一个n元组C=(c1, c2, …, cn)来描述图的一种可能着色,其中,ci∈{1, 2, …, m} (1≤i≤n)表示赋予顶点i的颜色。 例如,5元组(1, 2, 2, 3, 1)表示对具有5个顶点的无向图的一种着色,顶点1着颜色1,顶点2着颜色2,顶点3着颜色2,如此等等。 如果在n元组C中,所有相邻顶点都不会着相同颜色,就称此n元组为可行解,否则为无效解。
回溯法求解图着色问题,首先把所有顶点的颜色初始化为0,然后依次为每个顶点着色。在图着色问题的解空间树中,如果从根结点到当前结点对应一个部分解,也就是所有的颜色指派都没有冲突,则在当前结点处选择第一棵子树继续搜索,也就是为下一个顶点着颜色1,否则,对当前子树的兄弟子树继续搜索,也就是为当前顶点着下一个颜色,如果所有m种颜色都已尝试过并且都发生冲突,则回溯到当前结点的父结点处,上一个顶点的颜色被改变,依此类推。回溯法求解图着色问题,首先把所有顶点的颜色初始化为0,然后依次为每个顶点着色。在图着色问题的解空间树中,如果从根结点到当前结点对应一个部分解,也就是所有的颜色指派都没有冲突,则在当前结点处选择第一棵子树继续搜索,也就是为下一个顶点着颜色1,否则,对当前子树的兄弟子树继续搜索,也就是为当前顶点着下一个颜色,如果所有m种颜色都已尝试过并且都发生冲突,则回溯到当前结点的父结点处,上一个顶点的颜色被改变,依此类推。
1 A=1 2 B=2 A A 3 4 C=3 5 6 7 B C C B D=3 D=1 8 9 10 E=1 D E D E 11 12 13 14 (a) 一个无向图 (b) 回溯法搜索空间 图8.8 回溯法求解图着色问题示例
伪代码 算法8.1——图着色问题 1.将数组color[n]初始化为0; 2.k=1; 3.while (k>=1) 3.1 依次考察每一种颜色,若顶点k的着色与其他顶点的着色不发生冲突,则转步骤3.2;否则,搜索下一个颜色; 3.2 若顶点已全部着色,则输出数组color[n],返回; 3.3 否则, 3.3.1 若顶点k是一个合法着色,则k=k+1,转步骤3处理下一个顶点; 3.3.2 否则,重置顶点k的着色情况,k=k-1,转步骤3回溯; 设数组color[n]表示顶点的着色情况,回溯法求解m着色问题的算法如下:
算法8.2—— 图着色问题 C++描述
(xi, xi+1)∈E (1≤i≤n-1) (xn, x1)∈E xi≠xj (1≤i, j≤n,i≠j) 8.2.2 哈密顿回路问题 假定图G=(V, E)的顶点集为V={1, 2, …, n},则哈密顿回路的可能解表示为n元组X=(x1, x2, …, xn),其中,xi∈{1, 2, …, n} ,并有如下约束条件:
1 x1=1 2 x2=2 3 4 1 2 x3=3 3 5 6 7 x4=5 x4=4 5 4 8 9 11 10 17 x5=5 x5=4 12 13 14 15 16 19 18 20 21 (a) 一个无向图 (b) 哈密顿回路的搜索空间
伪代码 算法8.3——哈密顿回路问题 1.将顶点数组x[n]初始化为0,标志数组visited[n]初始化为0; 2.k=1; visited[1]=1; x[1]=1; 从顶点1出发构造哈密顿回路; 3.while (k>=1) 3.1 x[k]=x[k]+1,搜索下一个顶点; 3.2 若(n个顶点没有被穷举) 执行下列操作 3.2.1 若(顶点x[k]不在哈密顿回路上&&(x[k-1],x[k])∈E), 转步骤3.3; 3.2.2 否则,x[k]=x[k]+1,搜索下一个顶点; 3.3 若数组x[n]已形成哈密顿路径,则输出数组x[n],算法结束; 3.4 否则, 3.4.1 若数组x[n]构成哈密顿路径的部分解, 则k=k+1,转步骤3; 3.4.2 否则,重置x[k],k=k-1,取消顶点x[k]的访问标志, 转步骤3;
算法8.4——哈密顿回路问题 C++描述
8.3 组合问题中的回溯法 8.3.1 八皇后问题
8.3.1 八皇后问题 八皇后问题是十九世纪著名的数学家高斯于1850年提出的。问题是:在8×8的棋盘上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。可以把八皇后问题扩展到n皇后问题,即在n×n的棋盘上摆放n个皇后,使任意两个皇后都不能处于同一行、同一列或同一斜线上。
显然,棋盘的每一行上可以而且必须摆放一个皇后,所以,n皇后问题的可能解用一个n元向量X=(x1, x2, …, xn)表示,其中,1≤i≤n并且1≤xi≤n,即第i个皇后放在第i行第xi列上。 由于两个皇后不能位于同一列上,所以,解向量X必须满足约束条件: xi≠xj (式8.1) 若两个皇后摆放的位置分别是(i, xi)和(j, xj),在棋盘上斜率为-1的斜线上,满足条件i-j= xj-xi,在棋盘上斜率为1的斜线上,满足条件i-j= xi-xj,综合两种情况,由于两个皇后不能位于同一斜线上,所以,解向量X必须满足约束条件: |i- j|≠| xi-xj|(式8.2)
1 2 3 4 1 2 3 4 皇后1 皇后2 皇后3 皇后4 图8.11 四皇后问题 为了简化问题,下面讨论四皇后问题。 四皇后问题的解空间树是一个完全4叉树,树的根结点表示搜索的初始状态,从根结点到第2层结点对应皇后1在棋盘中第1行的可能摆放位置,从第2层结点到第3层结点对应皇后2在棋盘中第2行的可能摆放位置,依此类推。
回溯法求解4皇后问题的搜索过程 Q Q Q Q Q Q Q Q × × × Q × × Q × × × × (a) (b) (c) (d) (e) Q Q Q Q Q Q × × × Q Q Q × Q Q Q × × × × × × Q (f) (g) (h) (i) (j)
算法8.5——n皇后问题 C++描述
8.4 实验项目 • 实验内容 • 1) 哈密顿的回路算法 • 2) 八皇后问题 • 实验目的与要求 • 掌握回溯算法的设计思想; • 掌握空间树的构造方法,以及在求解过程中如何存储求解路径; • 考察回溯法求解问题的有效程度; • 选择任意一个问题,用回溯法实现; • 所有同学提交实验报告 电子稿 和 打印稿。
作业090508 • 内容: • P180 第4,5题。画出各自的搜索空间。 • 要求: • 严禁抄袭; • 下周五(5.15)准时提交(作业本);