1、2019/9/12,1,第5章 回溯法,2,学习要点 理解回溯法的深度优先搜索策略。 掌握用回溯法解题的算法框架 (1)递归回溯最优子结构性质 (2)迭代回溯贪心选择性质 (3)子集树算法框架 (4)排列树算法框架,3,通过应用范例学习回溯法的设计策略。 (1)装载问题; (2)批处理作业调度; (3)符号三角形问题 (4)n后问题; (5)0-1背包问题; (6)最大团问题; (7)图的m着色问题 (8)旅行售货员问题 (9)圆排列问题 (10)电路板排列问题,4,有许多问题,当需要找出它的解集或者要求回答什么解是满足某些约束条件的最佳解时,往往要使用回溯法。 回溯法的基本做法是搜索,或是一
2、种组织得井井有条的,能避免不必要搜索的穷举式搜索法。这种方法适用于解一些组合数相当大的问题。 回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。,回溯法,5,问题的解空间,问题的解向量:回溯法希望一个问题的解能够表示成一个n元式(x1,x2,xn)的形式。 显约束:对分量xi的取值限定。例如:Xi= 0,即Si=所有非负实数。 隐约束:为满足问题的解而对不同分量之间施加的约束,如满足某规范函数P(X1,X
3、n) 。 解空间:对于问题的一个实例,解向量满足显式约束条件的所有多元组,构成了该实例的一个解空间,注意: 同一个问题可以有多种表示,有些表示方法更简单,所需表示的状态空间更小(存储量少,搜索方法简单)。,6,例1:子集和数问题,已知n+1个正数:wi, 1in, 和M。要求找出wi 的所有子集使得子集内元素之和等于M。例如:n=4, (w1,w2,w3,w4)=(11,13,24,7),M=31则满足要求的子集是(11,13,7)和(24,7)。如果用满足条件的wi的下标表示解向量,则这两个解可表示为(1,2,4)和(3,4)。,7,子集和数问题的描述,所有的解是k-元组 (x1,xk) 1
4、kn。 其中 xi 是对应的 wi 的下标。 显示约束条件是要求 xi j | 1 j n 。 隐式约束条件则要求没有两个 xi 是相同的且相应的wi 的和数是 M。为了避免产生同一个子集的重复情况:(1,2,4) 和 (1,4,2) 表示同一个子集。为此,约定元组内分量按增序排列。,8,子集和数问题的另一种表示,每个子集由n-元组(x1,xn)表示, 其中xi 0,1 , 1 i n,表示:xi=0, 表示没有选择wi; xi=1, 表示选择wi; 则例中的解可以表示为大小固定的元组: (1,1,0,1)和(0,0,1,1),9,解空间的树结构,搜索算法通过系统地检索给定问题的解空间来确定问
5、题的解。所有这些检索技术可以用解空间的树结构加以描述。解空间的树结构称为状态空间树。,10,例1:子集和数问题(树表示),已知n+1个正数:wi,1in, 和 M。要求找出wi的和数是M的所有子集。例如:n=4, (w1,w2,w3,w4)=(11,13,24,7),M=31。则满足要求的子集是(11,13,7)和(24,7)。 如果用满足条件的wi的下标表示解向量,则这两个解可表示为(1,2,4)和(3,4)。 如果用一个n-元组(x1,xn)表示,它使得xi 0,1且1in。xi=0时,表示没有选择wi,xi=1时,表示选择wi。则这两个解可表示为(1,1,0,1)和(0,0,1,1)。
6、图1和图2给出了这两种情况下的树结构形式。,11,图1: 子集和数问题的一种解空间结构,结点按宽度优先检索方式编号,x2=2,(1); (1,2); (1,2,3); (1,2,3,4); (1,2,4); (1,3,4); (1,4); ,12,图2: 子集和数问题的另一种结构,结点按D-检索方式编号,13,有关状态空间树的术语,问题状态:树中的每一个结点确定所求解问题的一个问题状态。代表问题状态的结点称为问题结点 状态空间:由根结点到其它结点的所有路径确定了这个问题的状态空间。 解状态:是这样的一些问题状态S,对于这些问题状态,由根到S的那条路径确定了解空间的一个元组。其对应的结点称为解结
7、点。图1中,所有的结点都是解状态,图2中,只有叶子结点才是解状态。,14,有关状态空间树的术语,答案状态:是这样的一些问题状态S,对于这些问题状态,由根到S的那条路径确定了这问题的一个解(即它满足隐式约束条件)。 状态空间树:解空间的树结构。 静态树:状态空间树结构与所要解决的问题的实例无关。 动态树:状态空间树结构与所要解决的问题的实例相关。,15,有关状态空间树的术语(续1),状态空间树的每个问题结点对应一个子解空间,同时也代表已经作出的一些选择。状态空间树是在算法执行中产生的。为此定义以下术语。 活结点:已生成一个以上子节点,但所有子结点尚未全部生成的结点。 死结点:不再进一步扩展或已产
8、生了所有子结点的结点。 扩展(E-)结点:当前正在生成子结点的活结点。,16,状态空间树的产生方法,深度优先生成方法:一个E-结点展开一个子结点后,就让该子结点成为E-结点的状态生成方法(相当于对状态空间树做深度优先搜索),称为深度优先生成方法。 宽度优先的问题状态生成法:在一个扩展结点变成死结点之前,它一直是扩展结点。 回溯法:加限界的深度优先生成方法称为回溯法。 分枝限界法:如果一个结点成为E-结点并保持为E-结点直到变成死结点为止,这样的状态生成方法称为分枝限界法。在分枝限界法中要维持一个活结点表的结构,存放已生成但还未变为E结点的那些结点。,17,限界,设(x1,x2,xi1)是状态空
9、间树中由根到一问题结点A的路径;T (x1,x2,xi1)给出状态空间树上xi所有可能的取值,即 (x1,x2,xi)是状态空间树上到A的子节点的一条路径。 所谓限界函数Bi 是一谓词,如果路径(x1,x2,xi)不可能延伸到一个答案结点,则 Bi (x1,x2,xi)取false。限界即指停止产生该结点及以它为根的子树。,18,问题的解空间,n=3时的0-1背包问题用完全二叉树表示的解空间 (1,1,1),(1,1,0),(1,0,1),(1,0,0),(0,1,1),(0,1,0),(0,0,1),(0,0,0),19,例1:,n=3时的0-1背包问题,w=16,15,15p=45,25,
10、25 c=30,E-结点和活结点 死结点,R=14 V=45,Rw2 x,16 45,R=30 V=0,R=15 V=25,30 50,Rw3 x,R=0 V=50,15 25,15 25,0 0,20,例2:,旅行商问题,旅行线路 (1,2,4,3,1)(1,3,2,4,1)(1,4,3,2,1),例2:,旅行商问题,解空间树中叶结点个数为(n-1)!,(1,2,3,4,1) v=59,(1,2,4,3,1) v=66 x,(1,3,2,4,1) v=25,E-结点和活结点 死结点,22,回溯法的基本思想,(1)针对所给问题,定义问题的解空间; (2)确定易于搜索的解空间结构; (3)以深度
11、优先方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。,常用剪枝函数: 用约束函数在扩展结点处剪去不满足约束的子树; 用限界函数剪去得不到最优解的子树。,23,回溯法的基本思想,用回溯法解题的一个显著特征是在搜索过程中动态产生问题的解空间。在任何时刻,算法只保存从根结点到当前扩展结点的路径。如果解空间树中从根结点到叶结点的最长路径的长度为h(n),则回溯法所需的计算空间通常为O(h(n)。而显式地存储整个解空间则需要O(2h(n)或O(h(n)!)内存空间。,24,递归回溯,回溯法对解空间作深度优先搜索,因此,在一般情况下用递归方法实现回溯法。,void backtrack (int t)
12、 /t表示递归深度 if (tn) output(x); /n表示深度界限elsefor (int i=f(n,t);i=g(n,t);i+) / f(n,t),g(n,t)分别表示 /当前扩展结点未搜索过的子树的起始编号和终止编号xt=h(i); if (constraint(t) ,迭代回溯,采用树的非递归深度优先遍历算法,可将回溯法表示为一个非递归迭代过程。,void iterativeBacktrack () int t=1;while (t0) if (f(n,t)=g(n,t) for (int i=f(n,t);i=g(n,t);i+) xt=h(i);if (constrain
13、t(t) ,遍历子集树需O(2n)计算时间,void backtrack (int t) if (tn) output(x);elsefor (int i=0;i=1;i+) xt=i;if (constraint(t) ,子集树,排列树,遍历排列树需要O(n!)计算时间,void backtrack (int t) if (tn) output(x);elsefor (int i=t;i=n;i+) swap(xt, xi);if (constraint(t) ,28,5.2 装载问题,1 问题描述有一批共n个集装箱要装上2艘载重量分别为c1和c2的轮船,其中集装箱i的重量为wi,且,装载问
14、题要求确定是否有一个合理的装载方案可将这个集装箱装上这2艘轮船。如果有,找出一种装载方案。,29,5.2 装载问题,当n= 3,c1 =c2 = 50,w=10,40,40 时,可将货箱1 , 2装到第一艘船上,货箱3装到第二艘船上。w= 20,40,40时,则无法将货箱全部装船。 当c1 =c2 且货箱总重量为2c1时该问题等价于分划问题:能否将一组数分成两组使得各组内的数之和相等。这是NP难度问题。 如果双船装船问题存在可行解则按下述方法一定可找到。,30,装载问题,(1)首先将第一艘轮船尽可能装满; (2)将剩余的集装箱装上第二艘轮船。 将第一艘轮船尽可能装满等价于选取全体集装箱的一个子
15、集,使该子集中集装箱重量之和最接近c1。由此可知,装载问题等价于以下特殊的0-1背包问题。,用回溯法设计解装载问题的O(2n)计算时间算法。在某些情况下该算法优于动态规划算法O(minc1,2n)。,31,假定n= 4,w= 8 , 6 , 2 , 3 ,c1 = 12。状态空间树 限界方法1:设cw为已装重量,如cww(i)c1则杀死该子结点。限界方法2:设bestw为当前最优装船重量,设 r 为剩余货箱的总重量,如cw+r=bestw,则停止产生该结点及其子结点。 同时使用,例,32,2 算法设计 解空间:子集树 可行性约束函数(选择当前元素): 当前载重量cw当前最优载重量bestw搜索
16、到第i层子树,当in时,叶结点,if cwbestw then cwbestw 当in时,内部结点,xi=1, if cw+wi bestw then 进入左子树xi=0, 总可行,进入右子树,33,2 算法设计 时间:每个结点的计算时间: O(1)子集树中结点个数:O(2n)backtrack的计算时间: O(2n) 空间: O(n)递归栈空间,cw=8 9 6 5 2 3 0,void backtrack (int i) / 搜索第i层结点if (i n) / 到达叶结点if(cwbestw)bestw=cw;return; if (cw + wi = c) / 搜索左子树cw += wi
17、;backtrack(i + 1);cw -= wi; /搜索右子树 backtrack(i + 1); ,实例:n= 4,w= 8 , 6 , 2 , 3 ,c1 = 12backtrack(1),void backtrack (int i) / 搜索第i层结点if (i n) / 到达叶结点if(cwbestw)bestw=cw;return; r-=wi; /剩余集装箱的重量,/初始值为集装箱总重量wiif (cw + wi bestw) /搜索右子树 backtrack(i + 1);r+=wi;,3 改进算法: 引入上界函数, 剪去不含最优解的子树。,36,展开的部分状态空间树,A,
18、B,F,D,C,H,1 0,1 0,cw=0,cw=8,cw=8,cw=10,cw=8,cw + r = 11 = bestw,0,1,bestw=10,bestw=11,0,cw+w2c1 x,cw+w3c1,cw+w4c1 x,E,G,cw+w4c1,实例:n= 4,w= 8 , 6 , 2 , 3 ,c1 = 12,x,4 构造最优解 public class Loading static int n; /集装箱数static int w;/集装箱重量数组static int c;/第一艘轮船的载重量static int cw;/当前载重量static int bestw; /当前最优载
19、重量static int r;/剩余集装箱重量static int x;/当前解static int bestx;/当前最优解,public static int maxLoading(int ww,int cc,int xx) /初始化类数据成员n=ww.length-1;w=ww;c=cc;cw=0;bestw=0;x=new intn+1;bestx=new intn+1;/初始化rfor(int i=1;i=n;i+)r+=wi;/计算最优载重量 backtrack(1);System.out.println(“bestw=“+bestw);return bestw;,static v
20、oid backtrack (int i) /回溯算法/ 搜索第i层结点if (in) / 到达叶结点for(int j=1;j bestw) /搜索右子树xi = 0; backtrack(i + 1);r+=wi; ,public static void main(String args) int ww=0,8,6,2,3;int cc=12;int xx=new int 5;maxLoading(ww,cc,xx);for(int j=1;j=n;j+)System.out.println(“xj=“+xj); ,xj=1 xj=0 xj=0 xj=1 bestw=11,40,展开的部分
21、状态空间树,A,B,F,D,C,H,1 0,1 0,cw=0,cw=8,cw=8,cw=10,cw=8,cw + r = 11 = bestw,0,1,bestw=10,bestw=11,0,cw+w3c1,E,G,cw+w4c1,41,5 效率分析 时间复杂性: bestx可能被更新O(2n)次,算法的计算时间为: O(n2n)两种改进策略,使之减为O(2n) : 先运行只计算最优值的算法,得到最优装载量W,时间为O(2n),然后运行改进算法backtrack,将算法中的bestw置为W,在首次到达的叶结点处终止算法,返回最优解bestx.在算法中动态地更新bestx。在每个结点处更新bes
22、tx只需O(1)时间。,42,5.3 批处理作业调度,1 问题描述给定n个作业的集合J1,J2,Jn。每个作业Ji必须先由机器1处理,然后由机器2处理。 作业Ji需要机器j的处理时间为tji ,i=1,2,n,j=1,2 。对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间。所有作业在机器2上完成处理的时间和称为该作业调度的完成时间和 f = F2i, i=1,n。批处理作业调度问题要求对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小。,43,批处理作业调度,这3个作业的6种可能的调度方案是 1,2,3; 相应的完成时间和为:19, 1,3,2; 18, 2,1,
23、3; 20, 2,3,1; 21, 3,1,2; 19, 3,2,1; 19,例: n=3,44,2 算法设计 解空间:排列树,class Flowshop static int m, / 各作业所需的处理时间 x, / 当前作业调度 bestx, / 当前最优作业调度 f2, / 机器2完成处理时间f1, / 机器1完成处理时间f, / 完成时间和bestf, / 当前最优值n; / 作业数,static void Backtrack(int i) if (i n) for (int j = 1; j f1)?f2i-1:f1)+mxj2;f+=f2i;if (f bestf) Swap(x
24、i, xj);Backtrack(i+1);Swap(xi, xj);f1 - =mxj1;f - =f2i; ,static void Backtrack(int i) if (i n) for (int j = 1; j f1)?f2i-1:f1)+mxj2;f+=f2i;if (f bestf) Swap(xi, xj);Backtrack(i+1);Swap(xi, xj);f1 - =mxj1;f - =f2i; ,static void Backtrack(int i) if (i n) for (int j = 1; j f1)?f2i-1:f1)+mxj2;f+=f2i;if
25、(f bestf) Swap(xi, xj);Backtrack(i+1);Swap(xi, xj);f1 - =mxj1;f - =f2i; ,static void Backtrack(int i) if (i n) for (int j = 1; j f1)?f2i-1:f1)+mxj2;f+=f2i;if (f bestf) Swap(xi, xj);Backtrack(i+1);Swap(xi, xj);f1 - =mxj1;f - =f2i; ,static void Backtrack(int i) if (i n) for (int j = 1; j f1)?f2i-1:f1)
26、+mxj2;f+=f2i;if (f bestf) Swap(xi, xj);Backtrack(i+1);Swap(xi, xj);f1 - =mxj1;f - =f2i; ,static void Backtrack(int i) if (i n) for (int j = 1; j f1)?f2i-1:f1)+mxj2;f+=f2i;if (f bestf) Swap(xi, xj);Backtrack(i+1);Swap(xi, xj);f1 - =mxj1;f - =f2i; ,51,3 效率分析 时间复杂性: O(n!)每个结点耗费时间O(1);最大结点数O(n!),52,5.4
27、符号三角形问题,+ + - + - + + + - - - - + - + + + - + + - + - -+,下图是由14个“+”和14个“-”组成的符号三角形。2个同号下面都是“+”,2个异号下面都是“-”。,在一般情况下,符号三角形的第一行有n个符号。符号三角形问题要求对于给定的n,计算有多少个不同的符号三角形,使其所含的“+”和“-”的个数相同。,53,算法设计 解向量:用n元组x1:n表示符号三角形的第一行。xi=1 表示“-” , xi=0 表示“+” ,n :第一行符号个数 符号总数: n*(n+1)/2 可行性约束函数:当前符号三角形所包含的“+”个数与“-”个数均不超过n*
28、(n+1)/4 无解的判断:n*(n+1)/2为奇数 pn+1n+1: 符号三角形矩阵 count: 当前“-”个数 sum: 已找到的符号三角形个数,54,public static long computer(int nn) n=nn;count=0;sum=0;half=n*(n+1)/2;if (half%2=1) return 0;half=half/2;p=new int n+1n+1;for(int i=0; i=n;i+)for(int j=0; j=n;j+)pij=0;backtrack(1);return sum; ,static void backtrack(int t
29、) if(counthalf)|(t*(t-1)/2-counthalf)return;/剪去不满足约束的子树if(tn) sum+; /找到一个满足要求的三角形elsefor(int i=0;i2;i+)/子树p1t=i;count+=i;for(int j=2;j=t;j+)/该子树形成的三角形pjt-j+1=pj-1t-j+1pj-1t-j+2;count+=pjt-j+1;backtrack(t+1);for(int j=2;j=t;j+) /回溯恢复count-=pjt-j+1;count-=i; ,56,+ + - + - -,+ + + + + +,57,- - - + + +,
30、+ - - - + -,58,符号三角形问题,复杂度分析 计算可行性约束需要O(n)时间,在最坏情况下有 O(2n)个结点需要计算可行性约束,故解符号三角形问题的回溯算法所需的计算时间为 O(n2n)。,59,8-皇问题 (回溯法描述),8皇后问题可以表示成8-元组(x1,x8),其中xi是放在第i行的皇后所在的列号。于是,解空间由88个8-元组组成。 显示约束条件为Si=1,2,3,4,5,6,7,8,1i 8。 隐式约束条件之一为没有两个xi相同(即任意两个皇后不在同一列上)。将其加入到显式条件中,于是解空间的大小由88个元组减少到8!个元组。,60,61,5.5 n-皇后问题,n-皇后问
31、题是8 -皇后问题的推广。n个皇后将被放置在nn的棋盘上且使得没有两个皇后可以互相攻击。这是8 -皇后问题的推广,其解空间由n-元组(1,2,n)的n!个排列所组成。 n=1,解为1,n=2,3,无解。下图给出了当n=4时的树结构。像这样的一棵树称为排列树。树的边由xi的可能的取值标记。由i级到i+1级节点的边给出xi的值。解空间由从根节点到叶节点的所有路径定义。,62,图: 4-皇后问题解空间的树结构(节点按深度优先检索编号),63,图:用回溯法解4-皇后问题,1,2,18,F F,31,13,8,F,29,F,F F,14,F,F,F F,30,X1=1 X1=2,X2=1 X2=2 X2
32、=3 X2=4,B,X3=1,X4=1,2 X4=3,X3=1 X3=2 X3=3 X3=4,X3=1 X3=2 X3=3,4,X4=1,2 X4=3,4,X2=1,2 X2=3 X2=4,F,F,F,F,F F,F F,64,解向量:(x1, x2, , xn) 解空间:排列树 显约束:xi=1,2, ,n 隐约束:1)不同列:xixj2)不处于同一正、反对角线:|i-j|xi-xj| n:皇后个数 x:当前解 sum:当前已找到的可行方案数,算法设计,static long nQueen(int nn) n=nn;sum=0;x=new intn+1;for (int i=0;in) su
33、m+; /到达叶结点,搜索到一个解elsefor (int i=1;i=n;i+) xt=i;if (Place(t) Backtrack(t+1);,66,图:用回溯法解4-皇后问题,1,2,18,F F,31,13,8,F,29,F,F F,14,F,F,F F,30,X1=1 X1=2,X2=1 X2=2 X2=3 X2=4,B,X3=1,X4=1,2 X4=3,X3=1 X3=2 X3=3 X3=4,X3=1 X3=2 X3=3,4,X4=1,2 X4=3,4,X2=1,2 X2=3 X2=4,F,F,F,F,F F,F F,67,n-皇后问题,复杂度分析 时间:计算可行性约束需要O(
34、n)时间,在最坏情况下有 O(n!)个结点需要计算可行性约束,故解n-皇后问题的回溯算法所需的计算时间为 O(n*n!)。 空间: O(n)递归栈空间,68,5.6 0-1背包问题,解空间:子集树 可行性约束函数: 搜索策略:只要其左儿子结点是一个可行结点,搜索就进入其左子树。当右子树有可能包含最优解时才进入右子树搜索,否则将右子树剪去。r:当前剩余物品价值总和cp:当前价值bestp:当前最优价值cp+r bestp, 剪去右子树 上界:将剩余物品依其单位重量价值排序,然后依次装入物品,直至装不下时,再装入该物品的一部分而装满背包。,static double c ; /背包容量static
35、 int n; /物品数static int w; /物品重量数组static int p; /物品价值数组static double cw;/当前重量static double cp; /当前价值static int bestx;/当前最优价值,70,private static bound(int i) / 计算上界double cleft = c - cw; / 剩余容量double bound = cp;/ 以物品单位重量价值递减序装入物品,wi已排好序while (i = n ,实例:n=4, c=7, p= 9, 10, 7, 4 , w= 3, 5, 2, 1 价值/单位重量 3
36、, 2, 3.5, 4 x = 1, 0.2, 1, 1 最优值 22,71,static void backtrack (int i) /回溯算法/ 搜索第i层结点if (in) / 到达叶结点bestw=cp;return;/ 搜索子树if (cw + wi bestp) /进入右子树backtrack(i + 1); ,实例: n=8, P=(11,21,31,33,43,53,55,65 )M=110, W=( 1, 11,21,23,33,43,45,55 ) 贪心解:x=(1,1,1,1,1, 21/43,0,0)bound,164.88,1 11,12 32,33 63,56 9
37、6,160.22,89 139,164.66,163.81,139,162.44,99 149,149,161.63,101 151,151,159.81,66 106,96,109 159,160.18,159,159.77,157.55,159.76,157.44,155.11,73,0-1背包问题,复杂度分析 时间:计算上界需要O(n)时间,在最坏情况下有 O(2n)个结点需要计算可行性约束,故解该问题的回溯算法所需的计算时间为 O(n 2n)。 空间: O(n)递归栈空间,74,5.7 最大团问题(clique),给定无向图G=(V,E),令U为无向图G的顶点的子集,当且仅当对于U中的
38、任意点u 和v,(u , v)是图G的一条边时,U定义了一个完全子图(complete subgraph)。子图的尺寸为图中顶点的数量。当且仅当一个完全子图不被包含在G的一个更大的完全子图中时,它是图G的一个团。 G的最大团是指G中所含顶点数最多的团。,图a G,图b ,在图a 中,子集 1 , 2 是G的大小为2的完全子图,但不是一个团,它被包含在完全子图 1 , 2 , 5 中。 1 , 2 , 5 为一最大团。点集 1 , 4 , 5 和 2 , 3 , 5 也是最大团。 独立(顶点)集:无边相连的顶点集合且包含意义下最大. 最大独立集:顶点数最多的独立集.,76,如果UV且对任意u,v
39、U有(u,v)E,则称U是G的空子图。G的空子图U是G的独立集当且仅当U不包含在G的更大的空子图中。 对于任一无向图G=(V,E)其补图G=(V1,E1)定义为:V1=V,且(u,v)E1当且仅当(u,v)E。 图b 是图a 的(边)补图,反之亦然。 2 , 4 定义了图a 的一个空子图,它也是该图的一个最大独立集。 1 , 2 定义了图b 的一个空子图,它不是独立集,因为它被包含在 1 , 2 , 5 中。 2,3和1,2,5是图b 中图的独立集.1,2,5是最大独立集. G的团是其补图的独立集,反之亦然。 两个问题都是NP难度问题,77,团问题的状态空间树,最大团问题的一个状态空间树:元组
40、长度等于图的顶点数,分量取值0/1:xi=1表示顶点i在所考虑的集团中。所以状态空间树类似0/1背包问题的状态空间树。 检查根节点到达一问题节点的路径上的部分元组是否构成图的一个完全子图。 和装船问题相似,使用当前集团的顶点数cn剩余顶点数bestn 进行限界。,78,算法设计,解空间:子集树 可行性约束函数:顶点i到已选入的顶点集中每一个顶点都有边相连。 上界函数:有足够多的可选择顶点使得算法有可能在右子树中找到更大的团。 static int n; /图G的顶点数static int cn; /当前顶点数static int bestn; /当前最大顶点数static int x; /当前
41、解static int bestx; /当前最优解static boolean a; /图G的邻接矩阵,private static void Backtrack(int i) / 计算最大团if (i n) / 到达叶结点for (int j = 1; j = bestn) / 进入右子树xi = 0;Backtrack(i+1); ,1,2,11,8,7,16,9,17,X1=1 X1=0,X2=1 X2=0,X3=1,X4=1 X4=0,X3=1 X3=0,X2=1 X2=0,1与3不 相连,3,4,X4=1 X4=0,2与4不 相连,5,X5=1 X5=0,6,Bestn=3,cn+n
42、-i bestn ,X3=1 X3=0,10,Bestn=3,X5=1 X5=0,cn+n-i bestn ,cn+n-i bestn ,12,X4=1 X4=0,13,14,cn+n-i bestn ,X3=1 X3=0,15,X5=1 X5=0,cn+n-i bestn ,X4=1 X4=0,2与4不 相连,3与4不 相连,cn+n-i bestn ,cn+n-i bestn ,实例:,81,最大团问题,复杂度分析 最大团问题的回溯算法backtrack所需的计算时间显然为O(n2n)。 空间: O(n)递归栈空间,82,5.8 图的m着色问题,著名特例:四色问题证明平面或球面上的任何地图
43、的所有区域都至多可用四种颜色来着色,并使任何两个有一段公共边界的相邻区域没有相同的颜色。1976年 K.I.Apple, W.Haken, J.Koch 利用计算机证明了四种颜色足以对任何地图着色。,83,5.8 图的m着色问题,给定无向连通图 G 和 m 种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中每条边的2个顶点着不同颜色。这个问题是图的m可着色判定问题。若一个图最少需要m种颜色才能使图中每条边连接的2个顶点着不同颜色,则称这个数m为该图的色数。求一个图的色数m的问题称为图的m可着色优化问题。,84,算法设计 解向量:(x1, x2, , xn)表
44、示顶点i所着颜色xi ,xi 有m种可能的赋值。 基本状态空间树:度数为m,高为n+1的树。 可行性约束函数:顶点i与已着色的相邻顶点颜色不重复。static int n,m; /图的顶点数和可用色数static int x; /当前解static int a;/邻接矩阵 a 表示无向连通图。static long sum;/当前已找到的可m着色方案数 实例:n=3,m=3 的解空间树。,private static void backtrack(int t) if (tn) sum+;for (int i=1; i=n; i+)System.out.print(xi+“ “);System.
45、out.println();elsefor (int i=1;i=m;i+) xt=i;if (Ok(t)backtrack(t+1); private static boolean Ok(int k) / 检查颜色可用性for (int j=1;j=k;j+)if (akj=1) ,86,图的m着色问题,复杂度分析 图m可着色问题的解空间树中内结点个数是 对于每一个内结点,在最坏情况下,用Ok检查当前扩展结点的每一个儿子所相应的颜色可用性需耗时O(mn)。因此,回溯法总的时间耗费是,87,5.9 旅行商问题,在这个问题中,给出一个n 顶点网络(有向或无向),要求找出一个包含所有n 个顶点的具
46、有最小耗费的环路。任何一个包含网络中所有n 个顶点的环路被称作一个旅行(tour)。在旅行商问题中,要设法找到一条最小耗费的旅行。,88,例1: 一个四顶点网络,路径: 1,2,4,3,1;66 1,3,4,2,1;66 1,3,2,4,1;25 1,4,3,2,1;59 2,4,3,1,2;66 4,3,1,2,4;66 3,1,2,4,3;66,89,图2: 状态空间树,90,边上的编号代表一个城市 从城市1出发,经过城市2,n,最终回到城市1 叶结点代表最后经过的城市 状态空间树中每条路径上相邻的两条边的编号对应网络的一条边 从根到叶结点的一条路径上的编号为(2,n)的一个排列(permutation) 排列树,