Chapter 5
Backtracking
1
Objectives
• Describe the backtrack programming technique
• Determine when the backtracking technique is an
appropriate approach to solving a problem
• Define a state space tree for a given problem
2
Backtracking vs Dynamic Programming
• Dynamic Programming – subsets of a solution are generated
• Backtracking – Technique for deciding that some subsets
need not be generated
5.1 Backtracking Technique
• Problems: a sequence of objects is chosen from a specified set so
that the sequence satisfies some criterion.
• The classic example : is in the n-Queens problem.
3
• Goal: is to position n queens on an n×n chessboard so
that, no two queens may be in the same row, column,
or diagonal.
• The sequence in n-queen problem is the n positions
in which the queens are placed, the set for each
choice is the n2 possible positions on the chessboard. Q
• The n-Queens problem is a generalization of its Q
instance when n = 8, which is the instance using a Q
standard chessboard. Q
• We will illustrate backtracking using the instance Q
when n = 4. Q
N =6
4
depth-first search
1
2 8 11
3 4 7 9 10 12 13 16
5 6 14 15
Figure 5.1 depth-first search
• The nodes are numbered in the order in which they are visited.
• path is followed as deeply as possible until a dead end is reached.
• At a dead end we back up until we reach a node with an unvisited child, and
then we again proceed to go as deep as possible. 5
• Backtracking is a modified depth-first search of a tree
• A preorder tree traversal is a depth-first search of the tree.
• This means that
– the root is visited first, and
– a visit to a node is followed immediately by visits to all
descendants of the node.
• Although a depth-first search does not require that the
children be visited in any particular order, we will visit the
children of a node from left to right in the applications in this
chapter.
6
Function called by passing root at the top level
void depth_first_tree_search(node v)
{
node u;
visit v;
for( each child u of v)
depth_first_tree_searach(u);
}
7
• Consider n queens, n = 4.
• To simplify : no two queens can be in the same row.
• Assign to each queen a different row and checking which
column combinations yield solutions.
• Because each queen can be placed in one of four columns,
there are:
4 x 4 x 4 x 4 = 256 candidate solutions
• Nodes:
– Non-promising node: the node cannot lead to a solution
– Promising node: may lead to a solution
• If a node is non-promising, backtrack to the node’s parent and
proceed with the search on the next child
8
• We can create the candidate solutions by constructing a tree
in which the column choices for the first queen (the queen in
row 1) are stored in level-1 nodes in the tree , the column
choices for the second queen (the queen in row 2) are stored
in level-2 nodes, and so on. This tree is called a state space
tree
• A path from the root to a leaf is a candidate solution
• The entire tree has 256 leaves, one for each candidate
solution.
9
depth-first search
Start
1, 1 1, 2 1, 3 1, 4
2, 1 2, 2 2, 3 2, 4
3, 1 3, 2 3, 3 3, 4
The first few paths checked are as follows:
[<1, 1>, <2, 1>, <3, 1>, <4, 1>]
[<1, 1>, <2, 1>, <3, 1>, <4, 2>]
4, 1 4, 2 4, 3 4, 4
[<1, 1>, <2, 1>, <3, 1>, <4, 3>]
[<1, 1>, <2, 1>, <3, 1>, <4, 1>]
state space tree 10
• We can make the search more efficient as follows: no two queens can be in
the same column.
• This sign tells us that this node can lead to nothing but dead ends.
• Similarly, as illustrated in Fig. 5.3(b) .
(a) (b)
11
• Backtracking : a depth-first search of a state space tree, checking
whether each node is promising
• If it is nonpromising, backtracking to the node’s parent. This is
called pruning the state space tree,
• The subtree consisting of the visited nodes is called the pruned
state space tree.
• A general algorithm for the backtracking :
void checknode (node v)
{
node u;
if (promising ( v ) )
if ( there is a solution at v ) write the solution ;
else
for ( each child u of v )
checknode ( u );
}
12
Example 5.1
• n-Queens problem: the function promising must return
false if a node and any of the node’s ancestors place
queens in the same column or diagonal.
13
Start
1, 1 1, 2
2, 1 2, 2 2, 3 2, 4 2, 1 2, 2 2, 3 2, 4
c d
3, 1 3, 2 3, 3 3, 4 3, 1 3, 2 3, 3 3, 4 3, 1
c
4, 1 4, 2 4, 3 4, 4 4, 1 4, 2 4, 3
Figure 5.4 shows a portion of the pruned state space tree produced when
backtracking is used to solve the instance in which n = 4.
14
(a) < 1, 1 > is promising. { because queen 1 is the first queen
positioned }
(b) < 2, 1> is nonpromising. {because queen 1 is in column 1}
< 2, 2> is nonpromising. {because queen 1 is on left diagonal }
< 2, 3> is promising
(c) < 3, 1 > is nonpromising. { because queen 1 is in column 1 }
< 3, 2> is nonpromising. {because queen 2 is on right diagonal }
< 3, 3> is nonpromising. {because queen 1 is in column 1 }
< 3, 4> is nonpromising. {because queen 2 is on left diagonal }
(d) Backtrack to < 1, 1 >
< 2, 4> is promising
(e) < 3, 1> is nonpromising. {because queen 1 is in column 1 }
< 3, 2> is promising. {This is the second time we’ve tried < 3, 2> }
15
16
17
• There is some inefficiency in checknode, we check whether a node
is promising after passing it to the procedure. This means that
activation records for nonpromising nodes are unnecessarily placed
on the stack of activation records.
• We could avoid this by checking whether a node is promising before
passing it. A general algorithm for backtracking that does this is as
follows:
void expand (node v) void checknode (node v)
{ {
node u; node u;
for ( each child u of v ) if (promising ( v ) )
if (promising ( u ) ) if ( there is a solution at v )
if ( there is a solution at u ) write the solution ;
write the solution ; else
else for ( each child u of v )
expand ( u ); checknode ( u );
} }
18
5.2 The n-Queens Problem
• All solutions to N-Queens problem
• col (i ) : the column where the queen in the ith row is located
Promising function:
– 2 queens same column?
col(i) == col(k)
– 2 queens same diagonal?
col(i) – col(k) == i – k or col(i) – col(k) == k - i
col(2)=8, col(3)=1, col(6)=4,
col(2)- col(6)=4=6-2
Figure 5.6 The queen in row 6 is being threatened
in its left diagonal by the queen in row 3 and in its
right diagonal by the queen in row 2.
19
Q(0)
col(1)=1 col(1)=2 col(1)=3 col(1)=4
Q(1) Q(1) Q(1) Q(1)
col(2)=1 col(2)=2 col(2)=3 col(2)=4
Q(2) Q(2) Q(2) Q(2)
col(3)=1 col(3)=2 col(3)=3 col(3)=4
Q(3) Q(3) Q(3) Q(3)
20
Algorithm 5.1
The Backtracking Algorithm for the n-Queens Problem
• Problem: Position n queens on a chessboard so that no two
are in the same row, column, or diagonal.
• Inputs: positive integer n.
• Outputs: all possible ways n queens can be placed on an n × n
chessboard so that no two queens threaten each other.
• Each output consists of an array of integers col indexed from 1
to n, (col[i] is the position of the queen in the ith row .
21
void queens ( index i )
{
if (promising ( i ))
if ( i == n ) cout col [ 1 ] through col [ n ]
else
for (int j = 1; j <= n; j++){ // see if queen in (i+1) st row
col [ i + 1 ] = j; // can be positioned in each of
queens ( i + 1 ); // the nth column
}
}
bool promising ( index i )
{
index k; bool switch;
k = 1; switch = true;
while ( k < i && switch){ //check if any queen threatens
// queen in th ith row
if (col [ i ] == col [ k ] || abs ( col [ i ] - col[ k ]) == ( i - k ) switch = false;
k++;
}
return switch;
} 22
• In Algorithm 5.1, the main routine is queens.
• n and col are not inputs to the recursive routine
queens.
• The top-level call to queens : queens(0)
• In general, the problems in this chapter can be stated
to require one, several, or all solutions.
• It is a simple modification to make the algorithms
stop after finding one solution.
23
• Upper bound on number of nodes checked in pruned state
space tree by counting number of nodes in entire state space
tree:
– level 0 :1 node
– level 1 : n nodes
– level 2 : n2 nodes. . .
– level n : nn nodes
• The total number of nodes is
n n 1 1
1 n n n ... n
2 3 n
n 1
For the instance in which n 8, the state space tree contains
881 1
19,173,961 nodes
8 1
• This analysis is of limited value because the whole purpose of
backtracking is to avoid checking many of these nodes.
24
• To obtain an upper bound on the number of promising nodes: no
two queens can ever be placed in the same column.
• For example, consider the instance in which n = 8.
• The first queen can be positioned in any of the eight columns, the
second can be positioned in at most seven columns; once the
second is positioned, the third can be positioned in at most six
columns; and so on.
• Therefore, there are at most
1 + 8 + 8 7 + 8 7 6 + … +8! = 109 601 promising nodes
• Generalizing this result to an arbitrary n,
1 + n + n (n-1) + … +n! = promising nodes
• This analysis does not give us a very good idea as to the efficiency
of the algorithm for the following reasons: First, it does not take
into account the diagonal check in function promising.
• Therefore, there could be far less promising nodes than this upper
bound. Second, the total number of nodes checked includes both
promising and nonpromising nodes.
25
• Algorithm 1 : depth-first search without backtracking.
• The number of nodes it checks is the number in the state space tree.
• Algorithm 2 :no two queens can be in the same row or in the same
column. Algorithm 2 generates n! candidate solution
• Nqueen, n=8:
– promo 2057
– nonpromo 13664
26
Algorithm 5.4 Backtracking Algorithm for
Sum-of-Subsets
• Sum-of-Subsets problem: there are n positive integers
(weights) wi and a positive integer W.
• The goal is to find all subsets of the integers that sum to W.
27
Example 5.2
• S = {w1 = 5, w2 = 6, w3 = 10, w4 = 11, w5 = 16} and W=21
• Solutions:
– {w1 , w2 , w3 } : 5 + 6 + 10 = 21
– {w1 , w5 } : 5 + 16 = 21
– {w3 , w4 }: 10 + 11 = 21
28
Start
w1 0
0 0
w2 w2
w3 0 w3 0 w3 0 w3 0
w1+w2+w3 w1+w2
Figure 5.7 A state space tree for instances of the Sum-of-Subsets
problem in which n = 3.
29
Example 5.3
• n = 3 , W = 6 , w1 = 2, w2 = 4, w3 = 5
Start
w1= 2 2 0
2 0
w2= 4 4
0
4
0
6 2 4 0
w3= 5
5 0 5 0 5 0 5 0
11 6 7 2 9 4 5 0
Weight + wi+1 > W
30
• Sort weights in non-decreasing order before search
• weight : the sum of weights that have been included up to a
node at level i.
• total : the total weight of the remaining weights at a given
node.
• node at level i is non-promising if weight + w i+1 > W
• A node is non-promising if weight + total < W
31
Example 5.4
• Figure 5.9 shows the pruned state space tree when
backtracking is used with n = 4, W = 13, and , w1 = 3,
w2 = 4, w3 = 5, w4 = 6
32
0
w1= 3 3 0
3 0
w2= 4 4
0
4
0
7 3 4 0
w3= 5
5 0 5 0 5 0
12 7 8 3 9 4
w4= 6 6 0
weight + total < 13
13 7
weight + w i+1 > 13
5 nodes , expanded=15
2n+1 – 1= 25 – 1= 31 33
n = 13, W = 13, and , w1 = 3, w2 = 4, w3 = 5, w4 = 6, w5 = 13
0
w1= 3 3 0
3 0
w2= 4 4
0
4
0
7 3 4 0
w3= 5
5 0 5 0 5 0 5 0
12 7 8 3 9 4 5 0
0
w4= 6 6 0 6 6 6
0 0 6 0
13 7 9 3 10 4 11 5 6 0
0
w5= 13 13
13 0
5 nodes , expanded=27
2n+1 – 1= 26 – 1= 63 weight + total < 13
34
weight + w i+1 > 13
Algorithm 5.4
The Backtracking Algorithm for the Sum-of-
Subsets Problem
• Problem: Given n positive integers (weights) and a positive
integer W, determine all combinations of the integers that
sum to W.
• Inputs: positive integer n, sorted (nondecreasing order)
array of positive integers w indexed from 1 to n, and a
positive integer W.
• Outputs: all combinations of the integers that sum to W.
35
bool promosing (index i, int weight, int total)
{
return( weight + total>=W) && ( weight==W|| weight + w [ i + 1] <= W );
}
void sum_of_subsets (int i, int weight, int total )
{
if (promosing (i, weight, total))
if (weight==W)
cout include[1] through cout include[k]
else {
include [ i + 1 ] = "yes";
sum_of_subsets (i+1, weight + w [ i + 1 ], total – w [ i + 1 ] );
include[i+1]="no";
sum_of_subsets ( i + 1, weight, total – w [ i + 1 ] );
}
}
n
First call: Sum-of-Subsets(0, 0, total), total
j 1
w[ j ]
36
• The total number of nodes in the state space
searched by Algorithm 5.4
1 + 2 + 22 + . . . + 2n = 2n+1 – 1
• It could be that for every instance only a small
portion of the state space tree is searched.
• This is not the case. For each n, it is possible to
construct an instance for which the algorithm visits
an exponentially large number of nodes.
37