Professional Documents
Culture Documents
Backtracking
Backtracking
Consider the N Queens problem -- Discover if and how N Queens can be placed on an
N x N chessboard in non-attacking position. (There is a solution to the N Queens
problem for all boards of N ≥ 4)
This algorithm just specifies the order in which the nodes are to be "visited", it does not
include any instruction for what to do at a node when it is "visited".
The diagram below partially illustrates the state space tree for the instance of the N-
Queens problem when N = 4. the ordered pair (i, j) in each node indicates a possible row,
column placement of a queen. Each queen can be placed in one of the N columns for
each of the N rows, for a total of 4 x 4 x 4 x 4 = 256 candidate solutions. In general
therefore, there are NN candidate solutions.
For the N-Queens problem, a placement is "promising" if the placed queen is not in the
same column or same diagonal as one of the already positioned queens. To locate the
first solution to the 4-queens problem, the following nodes in state-space will be visited.
This traversal of state-space corresponds to the following attempts at positioning the
queens.
When none of the children nodes of a placed queen leads to a promising solution, the
algorithm backtracks and removes the last queen placed.
Obtain an upper bound for the number of "promising" nodes examined in the state
space.
When placeQueen( i ) is called, i queens have been placed in rows 0 .. i -1. There are
n(n - 1) …(n - i + 1) ways to place the first i queens when i > 0. When i = 0, there is 1
call to promising( ). Thus for each iteration of the for-loop in placeNQueens( ), the
number of "promising" nodes that are visited is less than or equal to:
n ∞
= n (n!) Σ 1/i! ≤ n (n!) (e -1) since Σ 1/i! = e
i=1 i=0
This bound must be multiplied by O(n) -- the run-time of promising( ) in our algorithm, but this
method can be reduced to O(1) if an array of diagonals used is maintained by NQueens. This
bound is also artificially high, because it ignores the number of nodes that are non-promising
because of the test for occupied diagonals. Still the worst-case bound on using a backtracking
algorithm to find all solutions to the NQueens problem is worse than exponential.
Consider of size K and we want to select from a set of n objects , where the ith object has
size si and value vi, a subset of these objects to maximize the value contained in the
knapsack with the contents of the knapsack less than or equal to K.
Suppose that K = 16 and n = 4, and we have the following set of objects ordered by their
value density.
i vi si vi/si
1 $45 3 $15
2 $30 5 $ 6
3 $45 9 $ 5
4 $10 5 $ 2
We will construct the state space where each node contains the total current value in the
knapsack, the total current size of the contents of the knapsack, and maximum potential
value that the knapsack can hold. In the algorithm, we will also keep a record of the
maximum value of any node (partially or completely filled knapsack) found so far.
When we perform the depth-first traversal of the state-space tree, a node is "promising" if
its maximum potential value is greater than this current best value.
We begin the state space tree with the root consisting of the empty knapsack. The current
weight and value are obviously 0. To find the maximum potential value we treat the
problem as if it were the fractional knapsack problem and we were using the greedy
algorithmic solution to that problem. We have shown that the greedy approach to the
fractional knapsack problem yields an optimal solution. We place each of the remaining
objects, in turn, into the knapsack until the next selected object is too big to fit into the
knapsack. We then use the fractional amount of that object that could be placed in the
knapsack to determine the maximum potential value.
k-1
totalSize = currentSize + Σ sj
j=i+1
k-1
totalSize = 0 + s1 + s2 = 0 + 3 + 5 = 8
From the root, we add two children at level 1 -- the node where the first item is included
in the knapsack and the node where it is not. For the child where the first item is not
included in the knapsack, the calculation for the bound proceeds as follows:
totalSize = 0 + s2 + s3 = 5 + 9 = 14
The state spaced traversed by the backtracking algorithm is displayed below. When the
bound of a node is less than or equal to the current maximum value, or adding the current
item to the node causes the size of the contents to exceed the capacity of the knapsack,
the subtrees rooted at that node are pruned, and the traversal backtracks to the previous
parent in the state space tree.
For the example problem this algorithm traverses the following state space:
For n objects, there are 2n possible solution sets -- the ith object is either in or out of the
solution set. The state space, therefore, is represented as a complete binary tree with 2n
leaves. Such a tree will have a total of 2n+1 - 1 nodes. The backtracking algorithm,
therefore, has a worst-case bound that is O(2n). With pruning the actual number of nodes
"visited" by the algorithm is much less.
The "brute force" algorithm tries all N! permutations of the N vertices to find all the
Hamiltonian cycles in the graph. The backtracking algorithm prunes unpromising
subtrees, but the algorithm is still O(n!).
public HamiltonianBacktrack(int [ ][ ] G) {
M = G;
N = M.length;
path = new int[N + 1];
}
private void hamiltonian(int index) {
if (promising(index) ) {
if (index == N -1) {
//print out the result
path[index+1] = path[0]; //first add the start vertex to the end
//of the cycle
System.out.print("A soulution is: ");
for (int i = 0; i <= N; i++)
System.out.print(" " + path[i]);
System.out.println( );
}
else
for (int j = 0; j < N; j++) { //try all vertices as the next one
path[index+1] = j;
hamiltonian(index+1);
}
}
}
private boolean promising(int index) {
if (index == 0) return true;
if (index == N -1 && M[path[index]][path[0]] == 0)
return false;
if (index > 0 && M[path[index-1]][path[index]] == 0)
return false;
int j = 0;
while (j < index && path[index] != path[j])
j++;
return (j == index);
}
public void hamiltonianPath(int startVertex) {
path[0] = startVertex;
hamiltonian(0);
}
}