You are on page 1of 25

Algorithm Design And Analysis Lab

ETCS-301

Case Study on Recursion and Backtracking in path


problems and games

Faculty: Mr Neeraj Garg Student Name:

Semester: Vth
Group:5C2
RollNo:

1
INDEX

S.NO TITLE PAGE


NO.
1. RECURSION 3-4
2. BACKTRACKING 5-6
3. PROBLEMS DISCUSSED 7-8
4. SUDOKU 9-13
5. Count board path 14
6. Snake and ladder 15-16
7. Rat in a maze 17-18
8. N-QUEENS 19-23
9. Knight’s tour 24-25

2
Recursion and Backtracking in path problems
and games

What is recursion?

Sometimes a problem is too difficult or too complex to solve because it


is too big. If the problem can be broken down into smaller versions of
itself, we may be able to find a way to solve one of these smaller versions
and then be able to build up to a solution to the entire problem. This is
the idea behind recursion; recursive algorithms break down a problem
into smaller pieces which you either already know the answer to, or can
solve by applying the same algorithm to each piece, and then combining
the results.

Stated more concisely, a recursive definition is defined in terms of itself.


Recursion is a computer programming technique involving the use of a
procedure, subroutine, function, or algorithm that calls itself in a step
having a termination condition so that successive repetitions are
processed up to the critical step where the condition is met at which time
the rest of each repetition is processed from the last one called to the first.

Recursion turns out to be a wonderful technique for dealing with many


interesting problems. Solutions written recursively are often simple.
Recursive solutions are also often much easier to conceive of and code
than their iterative counterparts.

What kinds of problems are well solved with recursion? In general,


problems that are defined in terms of themselves are good candidates
for recursive techniques.

3
The factorial function, often denoted as n!, describes the operation of
multiplying a number by all the positive integers smaller than it. For
example, 5! = 5*4*3*2*1. And 9! = 9*8*7*6*5*4*3*2*1.

Take a good close look at the above, and you may notice something
interesting. 5! can be written much more concisely as 5! = 5*4!.

And 4! is actually 4*3!.

int factorial(int n)
{
return n * factorial(n-1);
}

4
Backtracking Algorithm
Backtracking is an algorithmic-technique for solving problems
recursively by trying to build a solution incrementally, one piece at a
time, removing those solutions that fail to satisfy the constraints of the
problem at any point of time (by time, here, is referred to the time elapsed
till reaching any level of the search tree).
For example, consider the Sudoku solving Problem, we try filling digits
one by one. Whenever we find that current digit cannot lead to a solution,
we remove it (backtrack) and try next digit. This is better than naive
approach (generating all possible combinations of digits and then trying
every combination one by one) as it drops a set of permutations
whenever it backtracks.

Backtracking algorithm determines the solution by systematically


searching the solution space for the given problem. Backtracking is
a depth-first search with any bounding function. All solution using
backtracking is needed to satisfy a complex set of constraints. The
constraints may be explicit or implicit.

5
How to determine if a problem can be solved using
Backtracking?

Generally, every constraint satisfaction problem which has clear


and well-defined constraints on any objective solution, that
incrementally builds candidate to the solution and abandons a
candidate (“backtracks”) as soon as it determines that the
candidate cannot possibly be completed to a valid solution, can be
solved by Backtracking. However, most of the problems that are
discussed, can be solved using other known algorithms like
Dynamic Programming or Greedy Algorithms in logarithmic,
linear, linear-logarithmic time complexity in order of input size,
and therefore, outshine the backtracking algorithm in every respect
(since backtracking algorithms are generally exponential in both
time and space). However, a few problems still remain, that only
have backtracking algorithms to solve them until now. Consider a
situation that you have three boxes in front of you and only one of
them has a gold coin in it but you do not know which one. So, in
order to get the coin, you will have to open all of the boxes one by
one. You will first check the first box, if it does not contain the
coin, you will have to close it and check the second box and so on
until you find the coin. This is what backtracking is, that is solving
all sub-problems one by one in order to reach the best possible
solution. Consider the below example to understand the
Backtracking approach more formally, Given an instance of any
computational problem and data corresponding to the instance, all
the constraints that need to be satisfied in order to solve the
problem are represented by . A backtracking algorithm will then
work as follows: The Algorithm begins to build up a solution,
starting with an empty solution set .
S = {}
Add to the first move that is still left (All possible moves are
added to one by one). This now creates a new sub-tree in the
search tree of the algorithm. Check if satisfies each of the
constraints in .If Yes, then the sub-tree is “eligible” to add more
“children”. Else, the entire sub-tree is useless, so recurs back to
step 1 using argument .
In the event of “eligibility” of the newly formed sub-tree , recurs back
to step
6
RECURSION AND BACKTRACKING
PROBLEMS DISCUSSED
 Sudoku || Backtracking

 Counting Board Path || Recursion

7
 Snake and ladders || Recursion

 Rat In A Maze || Backtracking

 N-Queens || Backtracking

8
 Sudoku || Backtracking

Problem:
Given a partially filled 9×9 2D array ‘grid[9][9]’, the goal is to assign digits
(from 1 to 9) to the empty cells so that every row, column, and subgrid of
size 3×3 contains exactly one instance of the digits from 1 to 9.

Algorithm
Like all other Backtracking problems, we can solve Sudoku by one by
one assigning numbers to empty cells. Before assigning a number, we
check whether it is safe to assign. We basically check that the same
number is not present in the current row, current column and current 3X3
subgrid. After checking for safety, we assign the number, and recursively
check whether this assignment leads to a solution or not. If the
assignment doesn’t lead to a solution, then we try the next number for
9
the current empty cell. And if none of the number (1 to 9) leads to a
solution, we return false.

Find row, col of an unassigned cell


If there is none, return true
For digits 1 to 9
a) If there is no conflict for digit at row, col assign digit to row, col
and recursively try to fill rest in grid
b) If recursion successful, return true
c) Else, remove digit and try another
If all digits have been tried and nothing worked, return false

Now let’s try all this in practice with a simple 3x3 grid.

A 3x3 Sudoku puzzle


We start off by listing all the empty spots. If we label each cell in the grid with a
pair of numbers (x,y) and mark the first cell (1,1), then our empty spots will be at
locations:
(1,2)(2,2)(2,3)(3,1)(3,2)

We now select the first spot (1,2) to work with. Since this is a 3x3 grid, we have
numbers 1 to 3 at our disposal and no sub-grids to worry about (sub-grids are
only a bother for grids with squared sides, like 4, 9, 16 etc.).
Let’s place number 1 in this spot and see if it fits.

10
Filling ‘1’ in spot (1, 2)
It does. Great. We can now select the next spot on the list (2,2) and do the same
thing again. This time however, it fails. We already have a 1 in this row. This
means that we must abandon candidate and repeat step 2 with the next
number — which is 2.

Filling 2 in spot (2, 2)

Huzzah! One more spot is filled. Also, it might not look like it, but we did just
perform backtracking on a single spot. We abandoned a candidate solution (1 at
spot (2,2)), visited a previous stage (empty spot (2,2)) and explored a new
candidate solution (number 2 at spot (2,2)).
When we move on to spot (2,3), we have another problem. As you can see, we
are all out of options. None of the possible numbers fit in. This means that we
must now abandon candidate and repeat step 2 with the next number. Only this
time, we must visit spot (2,2) first to fix spot (2,3).

11
Failure to fill spot (2, 3)
We need to fill number 3 in spot (2,2) and that will resolve the issue.

Backtracking to spot (2, 2) and then re-visiting spot (2, 3)


We now repeat this process until with either reach the goal or we hit one of the
termination conditions.

Solved 3x3 Sudoku puzzle


However, consider the same grid with one small change. Replacing the 1 in
cell (3,3) with a 2 renders the grid unsolvable. Similarly, removing hints from
cells (2,1) and (3,3) allows for multiple solutions. But since this algorithm has a
single goal, it stops after the first solution is reached.

12
Unsolvable 3x3 puzzle (left) and Multi-solution 3x3 puzzle (right)

ALGORITHM COMPLEXITY :

O(n ^ m) where n is the number of possibilities for each square (i.e., 9 in classic
Sudoku) and m is the number of spaces that are blank.

Fig: all possible solutions of input sudoku


13
Counting Board Path || RECURSION
Here, we are given a source number say 0 and we have to reach a
destination say 10 on the board, and each time we roll a dice(1 to 6) We
move equivalent step forward on the board. So, we need to find total no.
of such solution from source to destination.
 Algorithm
countBoardPath(s,d)
//base condition
count=0;
for dice=1 to 6
count += countBoardPath(s+dice,d)
return count;

Fig: all possible solutions of board path

14
Snake and Ladder game || RECURSION
Given a snake and ladder board, the user is required to reach the
destination or last cell from source or 1st cell. we are given the user
history of dice thrown and we find where does the user end (WIN means
he/she reaches the destination).
If the player reaches a cell which is base of a ladder, the player has to
climb up that ladder and if reaches a cell is mouth of the snake, has to go
down to the tail of snake without a dice throw.

 code
snakesAnsladders(int src,int dest,int[] snakes,int[] moves,int mvidx)
if(src==0){
if(moves[mvidx]==1 || moves[mvidx]==6){
snakesAnsladders(1, dest, snakes, moves, mvidx+1);
}else{
snakesAnsladders(src, dest, snakes, moves, mvidx+1);
15
}
}else{
if(snakes[src]!=0){
snakesAnsladders(snakes[src], dest, snakes, moves, mvidx);
}else{
if(src + moves[mvidx] <= dest){
snakesAnsladders(src+moves[mvidx], dest, snakes, moves, mvidx
+1);
}else{
snakesAnsladders(src, dest, snakes, moves, mvidx+1);
}
}
}
}

A board of size 20 was taken and win is a situation where the user reaches 20
starting from 0 and can only start playing if he/she gets 1 or 6 first and in case the
user exhausts their moves and doesn’t reach the destination the final position
reached by the user is displayed

16
Rat in a maze || BACKTRACKING
A Maze is given as N*N binary matrix of blocks where source block is
the upper left most block i.e., maze[0][0] and destination block is lower
rightmost block i.e., maze[N-1][N-1]. A rat starts from source and has to
reach the destination. The rat can move in 8 directions: forward,
backward, up, diagonally upwards right, diagonally upwards left,
diagonally downwards right and diagonally downwards left,.
In the maze matrix, 0 means the block is a dead end and 1 means the
block can be used in the path from source to destination.
Naive Algorithm

The Naive Algorithm is to generate all paths from source to destination


and one by one check if the generated path satisfies the constraints.

while there are untried paths


{
generate the next path
if this path has all blocks as 1
{
print this path;
}}

Backtracking Algorithm
If destination is reached
Print the solution matrix
Else
a) Mark the current cell in solution as 1
b) Move forward in the horizontal direction and recursively
Check if this move leads to a solution.
c)If the move chosen in the above step doesn’t lead to a solution
then move in rest of the 7 directions and search for a solution.
17
d)If none of the above moves bring a solution the mark the cell
as 0
and return false

Fig: Example of rat in a maze problem

In the above figure when a 3*3 matrix is taken and certain path for
the movements of the rat are blocked, the solutions show how a rat
can move given he can move in 8 directions namely up, diagonally
north-east, right, diagonally south-east, down, diagonally south-
west, left and finally diagonally north-west

18
N Queen problem || BACKTRACKING

Problem Statement :
N queens problem is one of the most common examples of
backtracking. Our goal is to arrange N queens on an NxN chessboard
such that no queen can strike down any other queen. A queen can
attack horizontally, vertically, or diagonally.

What is Backtracking ?
Backtracking is finding the solution of a problem whereby the solution
depends on the previous steps taken. In backtracking, we first take a
step and then we see if this step taken is correct or not i.e., whether it
will give a correct answer or not. And if it doesn’t, then we just come
back and change our first step. In general, this is accomplished by
recursion. Thus, in backtracking, we first start with a partial sub-
solution of the problem (which may or may not lead us to the solution)
and then check if we can proceed further with this sub-solution or not.
If not, then we just come back and change it.
Thus, the general steps of backtracking are:
start with a sub-solution
check if this sub-solution will lead to the solution or not
If not, then come back and change the sub-solution and continue again

Initial Approach :
So, we start by placing the first queen anywhere arbitrarily and then
place the next queen in any of the safe places. We continue this process
until the number of unplaced queens becomes zero (a solution is found)
or no safe place is left. If no safe place is left, then we change the
position of the previously placed queen.

19
The above picture shows a 4x4 chessboard and we have to place 4
queens on it. So, we will start by placing the first queen in the first row.

Now, the second step is to place the second queen in a safe position.
Also, we can't place the queen in the first row, so we will try putting
the queen in the second row this time.

Let's place the third queen in a safe position, somewhere in the third
row.

Now, we can see that there is no safe place where we can put the last
queen. So, we will just change the position of the previous queen i.e.,
backtrack and change the previous decision.
20
Also, there is no other position where we can place the third queen, so
we will go back one more step and change the position of the second
queen.

And now we will place the third queen again in a safe position other
than the previously placed position in the third row.

We will continue this process and finally, we will get the solution as
shown below.

EXPLANATION OF THE CODE :

is_attack(int i,int j) → This is a function to check if the cell (i,j) is under


attack by any other queen or not. We are just checking if there is any
other queen in the row ‘i’ or column ‘j’. Then we are checking if there is
any queen on the diagonal cells of the cell (i,j) or not. Any cell (k,l) will
be diagonal to the cell (i,j) if k+l is equal to i+j or k-l is equal to i-j.

21
N_queen → This is the function where we are really implementing the
backtracking algorithm.

if(n==0) → If there is no queen left, it means all queens are placed and
we have got a solution.

if((!is_attack(i,j)) && (board[i][j]!=1)) → We are just checking if the


cell is available to place a queen or not. is_attack function will check if
the cell is under attack by any other queen and board[i][j]!=1 is making
sure that the cell is vacant. If these conditions are met then we can put a
queen in the cell – board[i][j] = 1.

if(N_queen(n-1)==1) → Now, we are calling the function again to place


the remaining queens and this is where we are doing backtracking. If this
function (for placing the remaining queen) is not true, then we are just
changing our current move – board[i][j] = 0 and the loop will place the
queen on some another position this time.

 Algorithm
The idea is to place queens one by one in different columns, starting
from the leftmost column. When we place a queen in a column, we
check for clashes with already placed queens. In the current column,
if we find a row for which there is no clash, we mark this row and
column as part of the solution. If we do not find such a row due to
clashes then we backtrack and return false.

1) Start in the leftmost column

2) If all queens are placed

return true

3) Try all rows in the current column.

Do following for every tried row.

a) If the queen can be placed safely in this row

then mark this [row, column] as part of the


22
solution and recursively check if placing

queen here leads to a solution.

b) If placing the queen in [row, column] leads to

a solution then return true.

c) If placing queen doesn't lead to a solution then

unmark this [row, column] (Backtrack) and go to

step (a) to try other rows.

3) If all rows have been tried and nothing worked,

return false to trigger backtracking.

The 1 values indicate placements of queens

0 0 1 0

1 0 0 0

0 0 0 1

0 1 0 0

23
The Knight’s tour || BACKTRACKING

Problem: The knight is placed on the first block of an empty board and,
moving according to the rules of chess, must visit each square exactly
once.
Following is chessboard with 8 x 8 cells. Numbers in cells indicate
move number of Knight.

Naive Algorithm for Knight’s tour


The Naive Algorithm is to generate all tours one by one and check if
the generated tour satisfies the constraints.

while there are untried tours

{ generate the next tour

if this tour covers all squares

{ print this path;}}

Backtracking works in an incremental way to attack problems.


Typically, we start from an empty solution vector and one by one add
items (Meaning of item varies from problem to problem. In context of
Knight’s tour problem, an item is a Knight’s move). When we add an
item, we check if adding the current item violates the problem
constraint, if it does then we remove the item and try other alternatives.
If none of the alternatives work out then we go to previous stage and
remove the item added in the previous stage. If we reach the initial
24
stage back then we say that no solution exists. If adding an item doesn’t
violate constraints then we recursively add items one by one. If the
solution vector becomes complete then we print the solution.

Backtracking Algorithm for Knight’s tour


Following is the Backtracking algorithm for Knight’s tour problem.

If all squares are visited

print the solution

Else

a) Add one of the next moves to solution vector and recursively

check if this move leads to a solution. (A Knight can make maximum

eight moves. We choose one of the 8 moves in this step).

b) If the move chosen in the above step doesn't lead to a solution

then remove this move from the solution vector and try other

alternative moves.

c) If none of the alternatives work then return false (Returning false

will remove the previously added item in recursion and if false is

returned by the initial call of recursion then "no solution exists" )

25

You might also like