第六章   回  溯  法  
 § 1. 回溯法的基本思想  
回溯法有“通用的解题法”之称。应用回溯法解问题时,首先应
该明确问题的解空间。一个复杂问题的解决往往由多部分构成,即,
一个大的解决方案可以看作是由若干个小的决策组成。 很多时候它们
构成一个决策序列。 解决一个问题的所有可能的决策序列构成该问题
的解空间。 解空间中满足约束条件的决策序列称为可行解。 一般说来,
解任何问题都有一个目标, 在约束条件下使目标达优的可行解称为该
问题的最优解。在解空间中,前 k 项决策已经确定的所有决策序列之
集称为 k 定子解空间。 0 定子解空间即是该问题的解空间。  
例 1.旅行商问题 : 某售货员要到若干个城市去推销商品。已知各  
个城市之间的路程(或旅费) 。他要选定一条从驻地出发,经过每个  
城市一次,最后回到驻地的路线,使得总的路程(或总旅费)最短。  
   我们用一个带权图 G(V, E)来表示,顶点代表城市,边表示城市之  
间的道路。图中各边所带的权即是城市间的距离(或城市间的旅费) 。  
 
                          30 
  
  
                                    5 
                      4                             
           6                                       10 
 
 
                              20 
 
                        具有四个顶点的带权图    
则旅行商问题即是: 在带权图G 中找到一条路程最短的周游路线,即 
A
C D
B
权值之和最小的Hamilton圈 。 
     如果假定城市 A是驻地。则推销员从A地出发,第一站有3 种选 
择:城市B、C 或城市D;第一站选定后,第二站有两种选择:如第 
一站选定B,则第二站只能选C、D 两者之一。当第一、第二两站都 
选定时,第三站只有一种选择:比如,当第一、第二两站先后选择了 
B 和C 时,第三站只能选择D。最后推销员由城市D 返回驻地A。推 
销员所有可能的周游路线可由下面的图反映出来 。  
  例 2. 定和子集问题:  已知一个正实数的集合  },,,{
2
1
n
wwwAL=  
和正实数 M.试求 A 的所有子集 S,使得 S 中的数之和等于 M。  
这个问题的解可以表示成 0/1 数组 (x
1
, x
2
, . . . , x
n
 ),依据 w
i
是否
属于 S, x
i
分别取值 1 或 0。故解空间中共有 2
n
个元素。它的树结构
是一棵完全二叉树 。  
  例 3. 4 皇后问题 : 在 4× 4 棋盘上放置 4 个皇后,且使得每两个之
间都不能互相攻击,即任意两个皇后都不能放在同一行、同一列及同
一对角线上。  
将 4 个皇后分别给以 1 到 4 的编号, 这个问题的解决就是要安排  
4 个皇后的位置。因而,每个决策序列由 4 个决策组成: P
1
, P
2
, P
3
,  
P
4
,这里 P
k
代表安排第 k 个皇后的位置,因而有 16 种可能。该问题  
的解空间有 16
4
个决策序列。这时的约束条件是 : 任意两个皇后均不  
能位于同一行、 同一列及同一个对角线上 。 注意到这个解空间比较大,  
从中搜索可行解较为困难。现在把约束条件中的“任意两个皇后均不  
在同一行 ” 也放在问题中考虑,即:将 4 个皇后放在 4× 4 棋盘的不  
同行上,使得每两个皇后均不能位于同一列、同一对角线上 。则解  
空间中共有 4
4
个决策序列,因为此时可以假定第 k 个皇后处于第 k 
行上。此时的约束条件为: 任意两个皇后均不能位于同一列及同一个  
对角线上。 事实上,我们还可以用另一种方法描述,使得解空间进一  
步缩小。将问题陈述为:将 4 个皇后放在 4× 4 棋盘的不同行、不同  
列上,使得 任意两个皇后均不能处在同一对角线上 。这时的解空间应  
当由 4!个决策序列构成。因为此时每个决策序列实际上对应于 {1, 2,  
3, 4}的一个排列。我们可以用树来描述解空间。  
          从例3来看,解空间的确定与我们对问题的描述有关。如何组织
解空间的结构会直接影响对问题的求解效率。 这是因为回溯方法的基
本思想是通过搜索解空间来找到问题的可行解以至最优解。 当所给的
问题是从 n 个元素的集合S 中找出满足某种性质的子集时, 相应的解
空间树称为子集合树。此时,解空间有
n
2 个元素,遍历子集树的任
何算法均需 )2(
n
? 的计算时间。如例2。当所给的问题是确定 n个元
素的满足某种性质的排列时,相应的 解空间树称为排列树,此时,解
空间有 !n 个元素。遍历排列树的任何算法均需 )!(n? 计算时间,如例
1 和例3。本章只讨论具有上两类解空间树的求解问题。 
确定了解空间的组织结构后,回溯法 就从开始顶点(解空间树的
根顶点)出发,以深度优先的方式搜索整个解空间。这个开始顶点就
成为一个活顶点, 同时也成为当前的扩展顶点。 在当前的扩展顶点处,
搜索向纵深方向移至一个新顶点。这个 新顶点就成为一个新的活顶
点,并且成为当前的扩展顶点。如果在当前的扩展顶点处不能再向纵
深方向移动,则当前的扩展顶点就成为死顶点。此时应往回移动(回
溯)至最近一个活顶点处,并使这个活顶点成为当前扩展顶点。回溯
法即以这种工作方式递归地在解空间中搜索, 直至找到要求的解或解
空间中已无活结点时为止。事实上,当我们将问题的有关数据以一定
的方式存储好以后(例如,旅行商问题存储赋权图的邻接矩阵、定和
子集问题是存储已知的 n+1 个数、4 皇后问题用整数对(i,j)表示棋
盘上各个位置) ,不必先建立一个解空间树,然后再搜索该树寻找所
需要的解。回溯法实际上在搜索的同时逐步生成解空间树(实际只需
要一部分) 。也就是说,对于实际问题我们不必要搜索整个解空间。
为了使搜索更加有效, 我们常常在搜索过程中加一些判断以决定搜索
是否该终止或改变路线。通常采用两种策略来避免无效的搜索,提高
回溯法的搜索效率。 其一是使用约束函数在扩展顶点处剪去不满足约
束的子树;其二是用限界函数(后面将阐述)剪去不能得到最优解的
子树。这两种函数统称为剪枝函数。 
运用回溯法解题通常包括以下三个步骤: 
1).针对所给问题,定义问题的解空间; 
2).确定易于搜索的解空间结构; 
3).以深度优先的方式搜索解空 间,并且在搜索过程中用剪枝函
数避免无效的搜索。 
§2.定和子集问题和 0/1 背包问题 
定和子集问题可以描述成下列的数 学问题:确定所有向量
),,,(
21 n
xxxxL= 满足: 
Mxw
nix
i
ni
i
i
=
=∈
∑
≤≤1
,,2,1},1,0{L
                 (7.1) 
如果让w
i
表示第i 件物品的重量,M 代表背包的容量,则0/1 背
包问题可以描述为:确定一个向量 ),,,(
21 n
xxxxL= 满足 
i
ni
i
i
ni
i
i
xpts
Mxw
nix
∑
∑
≤≤
≤≤
≤
=∈
1
1
max..
,,2,1},1,0{L
                 (7.2) 
这是一个优化问题,与定和子集问题比较,它多出优化函数,但只要
求确定一个最优解,定和子集问题要求确定所有可行解。我们先来处
理定和子集问题。 
(一).定和子集问题 
用回溯法求解的过程也即是生成解空间树的一棵子树的过程, 因为期
间将剪掉不能产生可行解的子 树(即不再对这样的子树进行搜索) 。
按照前面关于回溯算法的基本思想的说明, 搜索是采用深度优先的路
线,算法只记录当前路径。假设当前扩展顶点是当前路径的k 级,也
就是说当前路径上,x
i
,1 ≤i≤k 已经确定,算法要决定下一步搜索目
标。此时,有两种情况: 
                Mxw
i
ki
i
=
∑
≤≤1
   与   Mxw
i
ki
i
<
∑
≤≤1
 
前一种情况说明当前路径已经建立一个可行解, 当前扩展顶点即是一
个答案顶点。此时应停止对该路径的继续搜索,返回到前面最近活顶
点。后一种情况出现,算法需要判断是否需要继续向前搜索。显然,
只有当 Mwxw
nik
ii
ki
i
≥+
∑∑
≤≤+≤≤ 11
时才有必要继续向前搜索。如果集合
},,,{
2
1
n
wwwAL= 中的元素是按不降的次序排列的,则上述继续搜
索的条件还可以加强为  
MwxwandMwxw
ki
ki
i
nik
ii
ki
i
≤+≥+
+
≤≤≤≤+≤≤
∑∑∑
1
111
     (7.3) 
上述不等式记做B
k
。 
               定和子集问题的回溯算法伪代码 
SumSubset(s,k,r) // 寻找W[1:n]中元素和为 M 的所有子集。
//W[1:n]中元素按不降次序排列, 进入此过程时, X[1], . . . , 
//X[k-1]的值已经确定。 记
∑
?≤≤
=
11
][][
kj
jXjWs ,
∑
≤≤
=
njk
jWr ][  
  //假定W[1] ≤ M,
∑
≤≤
≥
nj
MjW
1
][  
1 global integer M, n; global real W[1:n];  
2 global boolean X[1:n]; 
3 real r, s; integer k, j; 
//由于B
k-1
=true,因此s + W[k] ≤ M 
4 X[k]=1; // 生成左儿子。 
5 if s + W[k]= M then 
         print (X[j],j from 1 to k); 
6 else 
7   if s + W[k] + W[k+1] ≤ M then  
8     SumSubset(s+W[k], k+1, r-W[k]); 
9   endif 
10 endif 
11 if s + r – W[k] ≥ M and s + W[k+1] ≤ M then  
12   X[k]=0; //生成右儿子 
13   SumSubset(s,k+1,r-W[k]); 
14 endif 
15 end SumSubset 
因为假定 W[1] ≤ M,
∑
≤≤
≥
nj
MjW
1
][ ,所以程序开始执行时,
B
0
=true。同样,程序在递归执行过程中,总是以前提条件 B
k-1
=true
开始处理第k级顶点的儿子们的生成过程,由第3~10语句完成,并
在此过程中决定是否转动生成下一级顶点的儿子的生成过程, 由11~
14语句完成。语句 11是一个判断条件,如果这个条件不能满足,则
没有必要生成k级顶点的右儿子。而在左儿子被生成后,语句4 和语
句7决定是否沿着这个左儿子继续搜索。 所以该算法所生成的子树的
叶顶点或是某个左儿子,此时找到一个可行解;或者是某个右儿子,
此时由根顶点到该顶点的路径不能延伸为可行解。 
例 子 : n=6,M=30; W[1:6]=(5 ,10,12,13,15,18). 由 算 法
SumSubset所生成的解空间树的子树参看文档SumSubset树。 
 
(二).0/1背包问题 
0/1背包问题是一个优化问题,因此 不仅可以使用约束函数,而且可以
使用限界函数做剪枝函数.如果当前背 包中的物品总重量是 cw,前面
k-1 件物品都已经决定好是否放入包中,那么第 k 件物品是否放入包
中取决于不等式cw + w
k 
≤ M 是否满足.这即是搜索的约束函数.另外,
我们可以如下确定限界函数.回忆可分割的 0/1 背包问题的贪心算法,
当物品的按照
11
//
++
≥
iiii
wpwp 的规则排序时,最优解是
)0,,0,,1,,1(),,,,,,(
111
LLLLtxxxxx
nlll
=
+?
的形式,其中, 10 ≤≤t .
设当前背包中物品的总效益值时cp,如下方式确定限界函数: 
                      构造限界函数 
 BoundF(cp,cw,k,M) //返回效益值的当前限界 
   gloal n, p[1:n],w[1:n]; 
   integer k,i; real b,c,cp,cw,M; 
   B=cp;c=cw; 
   for i from k+1 to n do 
c=c+w[i]; 
if c < M then b=b+p[i]; 
else return (b+(1-(c-M))/w[i])*p[i]; 
endif 
   endfor 
   return (b); 
end BoundF 
这样确定的限界函数表明,从当前确定的 k-1 定子解空间中寻求到的
可行解所能达到的效益值以当前限界函数的值为 上界.所以,如果搜
索最优解的算法在此之前已经知道大于 这个限界值的效益,则没有必
要在当前确定的 k-1 定子解空间中搜索.据此我们给出 0/1 背包问题
的回溯算法. 
            0/1背包问题的回溯算法 
 BackKnap(M,n,W,P,fw, fp,X)//M是背包容量.n件物品,数W[1:n] 
//和P[1:n] 分别表示重量和价值,fw 是背包的最后重量,fp 是 
//背包的最大效益.X[1:n]中美国元素取0或1值.若物品k未放 
//入背包,则X[k]=0;否则,X[k]=1. 
1   integer n,k,Y[1:n],I,X[1:n]; 
2   real M,W[1:n],P[1:n],fw,fp,cw,cp; 
3 cw=0; cp=0; k=1; fp=-1;  
4 loop 
5   while k≤n && cw+W[k]≤ M do //使用约束函数 
6     cw=cw+W[k]; cp=cp+P[k]; Y[k]=1; k=k+1; 
7   endwhile 
8   if k>n then  
9     fp=cp; fw=cw; k=n; X=Y;//修改解 
10   else Y[k]=0; 
11   endif 
12   while BoundF(cp,cw,k,M)≤fp do 
13     while k≠0 && Y[k]≠1 do 
14       k=k-1; 
15     endwhile 
16     if k=0 then return endif 
17     Y[k]=0;cw=cw-W[k];cp=cp-P[k]; 
18   endwhile 
19   k=k+1; 
20 endloop 
21 end BackKnap 
算法采用一个大的循环搜索各条可能的 路径.当一条路径的搜索到某
一步不能继续往下搜索时,此时或是因 为约束函数不满足,或是因为
限界函数不满足.它们分别在语句 5 ~7 的子循环和语句 12~18 的子循
环中达到 .这是程序的两个主要部分 ,其余主要时处理边界条件 ,如 k > 
n 的验证等 . 第一种情况出现时 ,语句 8~11 给出部分处理 ,剩下的事情
交给语句 12~19 来处理 .这里给出了搜索退回的方案 .  
§3.n-皇后问题和旅行商问题 
在第一节已经给出了这两个问题的解空间.如果用
),,,(
21 n
xxxL表示解,则它是自然数 },,2,1{ nL的一个排列.对于旅
行商问题,我们可以假定 1
1
=x ,表示售货员的驻地是城市 1.采用回
溯方法,对于 n 皇后问题,主要任务是给出约束函数,对于旅行商问题
主要是限界函数,因为此时我们可以假 定带权图是完全图,这只要将
实际不相邻的两个顶点间用带有权 ∞的边连接即可. 
(一).n-皇后问题 
这里的约束条件是: 任何两个皇后都不能位于同一对角线上.如
果我们用 ),( ji 表示棋盘上第i行与第j列交叉的位置.则在同一条平
行于主对角线的对角线上的两点 ),( ji 和 ),( lk 满足关系式 lkji ?=? ;
而处于同一条平行于副对角线的对角线上的两点 ),( ji 和 ),( lk 则满足
关系式 lkji +=+ .将这两个关系式略作变形记得 
|||| ljki ?=?                 (7.3.1) 
反之,如果棋盘上的两点 ),( ji 和 ),( lk 满足关系式 (7.3.1),则它们一
定位于同一条对角线上.所以,如果 ),,,(
21 n
xxxL是 n 皇后问题的一
个可行解,则对任何 ki ≠ ,等式 
||||
ki
xxki ?=?                 (7.3.2) 
均不得成立.这即是约束条件. 如果假定前面的 k-1 个皇后位置已经
排好,现在要安排第 k 个皇后的位置,必须使得
ki
xx ≠ ,而且等式
(7.3.2)不成立, 1,,2,1 ?= kiL.算法可以这样设计,对于
k
x 所有可
能的取值,验证上述条件,对于满足条件的 k 取最大者.而对于每个取
值
k
x ,验证它是否满足上述两个条件,用一个 boolean 函数 Place 来
完成. 
                     
  Place(k)//如果第k个皇后能放在第X[k]列,则返回true,否则返 
//回false.X 是一个全程数组,进入此过程时已经设置了k 个值 
global X[1:k]; integer i,k; 
i=1; 
        
while i<k do 
if X[i]=X[k] or |X[i]-X[k]|= |i-k| then 
  return (false); 
endif 
i=i+1; 
    endwhile 
    return (true); 
end Place 
使用函数Place 能使求n-皇后问题的回溯算法具有简单的形式 
               求n-皇后问题可行解的回溯算法 
nQueens(n)  
  integer k,n,X[1:n]; 
X[1]=0; k=1; //k是当前行,X[k]是当前列 
while k>0 do 
  X[k]=X[k]+1;//转到下一列 
  while X[k]≤ n && Place(k)=false do 
    X[k]=X[k]+1; 
  endwhile 
  if X[k]≤ n then 
    if k=n then 
      Print(X); 
    else k=k+1; X[k]=0; //转到下一行 
    endif 
  else k=k-1;//回溯 
  endif 
endwhile 
 end nQueens 
程序 nQueens 处理 4- 皇后问题的执行过程参看文档”4-皇后结构
树”. 
(二).旅行商问题 
用 1,2,…,n 代表 n 个顶点,一个周游
121
iiii
n
L用数组 ),,,(
21 n
iiiL表
示,它是旅行商问题的一个可行解.如果可行解的前 k-1 个分量
121
,,,
?k
xxxL已经确定,则判定
kk
xxxx
121 ?
L能否形成一条路径,只
需做k-1 次比较: 
,,,,
121 ?
≠≠≠
kkkk
xxxxxxL           (7.3.3) 
此即构成旅行商问题的约束条件.用 w(i,j)记边(i,j)的权值.cl 记
当前路径
121 ?k
xxxL的长度,即
∑
?≤≤
+
=
21
1
),(
ki
ii
xxwcl  .如果当前知道
的最短周游的线路路长度为fl,则当 
                  flkkwcl >?+ ),1(                  (7.3.4) 
时, 
kk
xxxx
121 ?
L不会是最短周游路线的一部分,在解空间树中,相
应的一枝被剪掉,(7.3.4)即是旅行商问题的限界条件.此外, 当 nk =
时,若 
                 flkwkkwcl <+?+ )1,(),1(            (7.3.5) 
则算法需要更新 fl,令 
)1,(),1( kwkkwclfl +?+=             (7.3.6) 
                    旅行商问题的约束条件函数                  
NextValue(k) //从顶点 1 出发的路径,如果第 k 个顶点是顶点
//X[k],则返回 true,否则返回 false.X 是一个全程数组,进入
//此过程时已经设置了 k 个值,其中 X[1]=1, X[k]是当前扩展
//顶点。 
global X[1:k]; integer i,k; 
i=1; 
        
while i<k do 
if X[i]=X[k] then 
  return (false); 
endif 
i=i+1; 
    endwhile 
    return (true); 
end NextValue 
使用函数NextValue能使求旅行商问题的回溯算法具有简单的形式 
               求旅行商问题的回溯算法 
BackTSP(n,W) // 求图G的从顶点1出发的最短周游 (Hamilton圈)
//路线。W是G的邻接矩阵。X[k]是当前路径的第k个顶点,c是
//当前路径的长度,fl 是当前所知道的最短的周游(Hamilton 
//圈)的长度  
  integer  k,n,X[1:n]; 
  real W[1:n,1:n],cl,fl; 
X[2]=1; k=2; cl=0; fl=+∞; 
while k>1 do 
  X[k]=(X[k]+1) mod n;//给X[k]预分配一个值  
  for j to n do 
if NextValue(k)=true then exit; endif 
    X[k]=(X[k]+1) mod n;  
  endfor 
  if [fl ≤ cl+W[k-1,k]] or [k=n and fl<cl+W[k-1,k]  
+W[X[n],1]] then k=k-1; //回溯 
elif k=n && fl≥cl+W[k-1,k]+W[X[k],1] then 
fl= cl+W[k-1,k]+W[X[k],1]; k=k-1; //回溯 
else cl= cl+W[k-1,k]; k=k+1;//继续纵深搜索 
endif  
    endwhile 
 end BackTSP 
 
§4 图的着色问题 
已知一个无向图G 和m 种颜色, 在只准使用这 m种颜色对图G的顶点
进行着色的情况下,是否有一种着色方法,使图种任何两个相邻的顶
点都具有不同的颜色?如果存在这样的着色方法,则说图 G 是 m-可
着色的,这样的着色称为图 G 的一种 m-着色。使得 G 是 m-可着色的
最小数m 称为图G 的色数。这一节所讨论的图的着色问题是: 
   给定无向图G 和m 种颜色,求出G 的所有m-着色 。 
   用 G 的邻接矩阵 W 表示图 G,W[i,j]=1 表示顶点 i 与 j 相邻(有
边相连) ,否则W[i,j]=0. m 种颜色分别用1,2,…,m 表示。图G 的
每一种m-着色都可以用一个 n-维数组 X[1:n]表示。 X[i]=k表示顶点
i 被着上颜色k。简单分析可知,解空间是一个完全的 m-叉树,共有
n+1 级。X 是可行解,当且仅当 
          W[i,j]=1 ? X[i]≠X[j],           (7.4.1)
 
此即是约束条件。假如已经给前 j-1 个顶点着好颜色,即
X[1],…,X[j-1]已经确定,则确定第 j个顶点所着的颜色X[j]时,根
据约束条件,应该验证条件 
          W[i,j]=1 ? X[i]≠X[j], 1≤i<j              (7.4.2) 
是否满足。这可以由下面程序完成。 
                下一步选色算法  
  NextColor ( j ) //进入此过程前,X[1],…,X[j-1]已经确定且满足约
//束条件。本过程给 X[j]确定一个整数 k,0 ≤k≤m:如果还有一
//种颜色 k可以分配给顶点 j(满足约束条件) ,则令X[j]=k;
//否则,令X[j]=//0。  
   global integer m, n, X[1:n], W[1:n, 1:n]; 
   integer j, k; 
   loop 
X[j]=(X[j]+1) mod (n+1); 
if X[k]=0 then return endif 
for i from 1 to j-1 do //验证约束条件  
  if W[i, j]=1 && X[i]=X[j] then exit endif 
endfor 
if i=j then return endif //找到一种颜色  
   endloop 
 end NextColor 
在程序 NextColor 开始执行之前,诸 X[k]均已经有值。这可在着色问
题的回溯算法初次调用该函数时赋予初值: X[i]=0,i=1,2,…,n。  
               图的着色问题回溯算法  
  GraphColor( k) // 采用递归。 W[1:n, 1:n]是图 G 的邻接矩阵, 1, 2, 
// . . . , m 代表 m 种颜色。 k 是下一个要着色的顶点。  
    global integer m, n, X[1:n], W[1:n, 1:n] ;  
    loop 
NextColor ( k ); // 确定 X[k]的取值  
if X[k]=0 then exit endif //说明没有颜色可以分配给第 k 个点  
if k=n then  // 已经找到一种着色方法  
  print (X); 
else GraphColor ( k+1 ) ; //递归  
endif 
   endloop 
end GraphColor 
例子 : n= 4, m= 3,  
无向图 G 如右图                     G 
 
1
4 3
2
                   
x
1
=                 1         2          3 
                                                                  
                                                                   
                                                                         
x
2
=     2      3            1     3           1       2 
                                                                      
                                                                             
                                                                     
                                                                   
x
3
= 1     3   1    2    2    3   1    2    2   3     1    3  
                                                              
                                                               
                                                               
x
4
=2  3   2  2  3  3  1   3  1  3   1  3  1  1    2  2 1    2       
                                                                  
                                                                        
                                                                
           一个 4 顶点的图和所有可能的 3 着色  
正好用 3 种颜色的解只有 12 个。  
 
§5 回溯法的效率分析  
回溯法是以深度优先的方式系统地搜索问题的解空间。 解空间是由
所有可能的决策序列 ),,,(
21 n
xxxL构成。在搜索过程中,采用剪枝函
数尽量避免无意义的搜索。通过前面的具体实例的讨论容易看出,一
个回溯算法的效率在很大程度上依赖于以下几个因素:  
1). 产生
k
x 的时间;  
2). 
k
x 的取值范围;  
3). 计算约束函数的时间;   
4). 计算限界函数的时间;  
5). 满足约条件及限界条件的
k
x 的个数。  
一般来说,一个好的约束函数能够显著地减少所生成的顶点的数
目。但是,这样的约束函数往往计算量较大。因此在选择约束函数是
通常存在着顶点数与约束函数计算量之间的折中。 我们希望总的计算
时间较少。为了提高效率,通常采用所谓的“重排原理” 。对于许多
问题而言,在进行搜索试探时,选取
k
x 值的顺序是任意的。这提示
我们,在其它条件相当的前提下,让可取值最少的
k
x 优先。这将会
更有效。如文档“解空间树比较” 中的图,是同一个问题的不同的解
空间树,从中可以体会到这种策略的效力。  
在第一个图中,若从第 1 层剪去一棵子树,则从所有应当考虑三元
组中一次消去 12 个三元组;在第二个图中,虽然同样从第 1 层剪去
一棵子树,却只从应当考虑的三元组中一次消去 8 个三元组。前者的
效果显然比后者好。  
解空间的结构一经选定,影响回溯法效率的前三个因素就可以确
定,只剩下生成顶点的数目是可变的,它将随问题的具体内容以及定
的不同生成方式而变动。即使是对于同一问题的不同实例,回溯法所
产生的顶点的数目也会有很大变化。对于一个实例,回溯法可能只产
生 )(nO 个顶点。而对于另一个相近的实例,回溯法可能产生解空间
中的所有顶点。如果解空间的顶点数是
n
2 或 !n ,则在最坏情况下,
回溯法的时间耗费一般为 )2)((
n
npO 或 )!)(( nnqO 。其中, )(np 和
)(nq 均为 n的多项式。对于一个具体问题来说,回溯法的有效性往往
就体现在当问题实例的规模 n较大时,它能够用很少的时间求出问题
的解。而对于一个问题的具体实例,我们又很难预测回溯法的算法行
为。特别地,很难估计在解这一具体实例时所产生的顶点数。这是在
分析回溯法效率时遇到的主要困难。 下面所介绍的概率方法也许对解
决这个问题有所帮助。  
 当用回溯法解某一个具体问题实例时 ,可用蒙特卡罗方法估算回
溯法将要产生的顶点数目。 该方法基本思想是在解空间树上产生一条
随即路径,然后沿此路径来估算结空 间中满足约束条件的顶点数 m。
设 x 是所产生的随即路径上的一个顶点, 且位于解空间树的第 i 层上。
对于 x 的所有儿子顶点,用约束函数 检测出满足约束条件的顶点数
m
i
。路径上的下一个顶点是从 x 的 m
i
个满足约束条件的儿子顶点中
随机选取的。 这条路径一直延伸到一个叶顶点或一个所有儿子顶点都
不满足约束条件的顶点为止。通过这些 m
i
的值,就可估计出解空间
树中满足约束条件的顶点的总数 m。 在用回溯法求问题的所有可行解
时,这个数特别有用。因为在这种情况下,解空间所有满足约束条件
的顶点都必须生成。若只要求用回溯法找出问题的一个解,则所生成
的顶点一般只是 m 个满足约束条件的顶点中的一部分。此时用 m 来
估计回溯法生成的顶点数就过于保守了。  
为了从 m
i
的值求出 m 的值,还需要对约束函数做一些假定。在估
计 m 时,假定所有约束函数是静态的,即在回溯法执行过程中,约
束函数并不随随算法所获得信息的多少而动态地改变。 进一步还假定
对解空间树中同一层的顶点所用的约束函数是相同的。 对于大多数回
溯法,这些假定都太强了。实际上,在大多数回溯法中,约束函数是
随着搜索过程的深入而逐渐加强的。在这种情形下,按照前面所做假
定来估计 m 就显得保守。如果将约束函数变化的因素也加进来考虑,
所得出的满足约束条件的顶点总数将会少于 m,而且会更精确些。  
在静态约束函数假设下,第一层共有 m
0
个满足约束条件的顶点。
若解空间的同一层的顶点具有相同的出度, 则在第一层上的每个顶点
将会又 m
1
儿子满足约束条件。因此,第二层将会又 m
0
m
1
个满足约束
条件的顶点。同理,第三层上满足约束条件的顶点个数是 m
0
m
1
m
2
。
依此类推,第 i+1 层上满足约束条件的顶点的数目是 m
0
m
1
m
2
… m
i
.因
此,对于给定的实例,如果产生解空间树上的一条途径,并求出 m
0
,
m
1
, m
2
,…, m
i
,…,则可以估计出回溯法要生成的满足约束条件的
顶点数目m=  m
0
+ m
0
m
1
+ m
0
m
1
m
2
+…. 
 假定回溯法要找出所有的可行解。设 ),,,(
121 ?i
xxxL是解空间树
中由根到一个顶点的路径,而 ),,,(
121 ?i
xxxTL表示所有这样的
i
x ,
使得 ),,,,(
121 ii
xxxx
?
L能够成为解空间树中的一条路径。 B
k
表示第 k
层上约束函数, B
k
(X[1], …,X[k])=true 表示这条路径到目前为止
未违背约束条件。否则 B
k
(X[1], …,X[k])=false。 
                回溯法的递归流程 
RecurBackTrack(k)//进入算法时,解向量X[1:n]的前k-1个分 
//量X[1],…,X[k-1]已经赋值 
global n, X[1:n]; 
for 每个满足   
    “X[k] ∈ T
k
(X[1], …,X[k-1]) && B
k
(X[1], …,X[k])=true” 
    的X[k] do 
    if (X[1], …,X[k]) 是一条抵达某一答案顶点路径 then 
       print (X[1], …,X[k]); 
    endif 
    RecurBackTrack(k+1) 
  endfor 
end RecurBackTrack 
根据前面的分析,我们不能给出回溯法递归流程生成的解空间树中
顶点数目m。 
              回溯法效率估计 
 Estimate //程序沿着解空间树中一条随机路径估计回溯法生成的顶  
//点总数 m 
m=1; r=1; k=1; 
loop 
  T
k
={X[k]| X[k]∈ T
k
(X[1], …,X[k-1]) && B
k
(X[1], …, 
X[k])=true}; 
        If T
k
={} then exit endif 
        r=r*size(T
k
); m=m+r; 
        X[k]=Choose(T
k
);  k=k+1; 
endloop 
return (m); 
   end Estimate  
其中 Choose(T
k
)是从 T
k
中随机地挑选一个元素。  
当用回溯法求解某个具体问题时, 可用算法 Estimate 估算回溯法
生成的顶点数。 若要估计得精确些, 可选取若干条不同的随机路径 (通
常不超过 20 条) ,分别对各随机路径估计顶点总数,然后以平均值作
为 m。  
例如 8 皇后问题,回溯算法 nQueens 可以用 Estimate 来估计。
文档“效率分析例图 ”给出了算法 Estimate 产生的 5 条随机路径所相
应的 8× 8 棋盘状态。当需要在棋盘上某行放入一个皇后时,所放的
列时随机选取的。它与已在棋盘上的其它皇后互不攻击。在图中棋盘
下面列出了每层可能生成的满足约束条件的顶点数,即 m
0
, m
1
,
m
2
,…, m
i
,…,以及由此随机路径算出的顶点总数 m 的值。这 5
个总点数的均值为1702。注意到8 皇后解空间树的顶点总数是:           
∑∏
= =
?+
7
0 0
)8(1
j
j
i
i =109601 
1702/109601≈1.55%,可见,回溯法效率远远高于穷举法。  





