0% found this document useful (0 votes)
14 views

Back Tracking Algorithm

The document discusses backtracking algorithms. It explains that backtracking is a technique for solving problems by incrementally building candidates to solutions and abandoning candidates that cannot be completed. It provides examples like the eight queens puzzle and constraint satisfaction problems. It also describes the basic steps of backtracking algorithms including recursively exploring solutions and backtracking when solutions cannot be completed.

Uploaded by

harshitha8712
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views

Back Tracking Algorithm

The document discusses backtracking algorithms. It explains that backtracking is a technique for solving problems by incrementally building candidates to solutions and abandoning candidates that cannot be completed. It provides examples like the eight queens puzzle and constraint satisfaction problems. It also describes the basic steps of backtracking algorithms including recursively exploring solutions and backtracking when solutions cannot be completed.

Uploaded by

harshitha8712
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

BACK TRACKING ALGORITHM

Backtracking is a class of algorithms for finding solutions to some computational problems,


notably constraint satisfaction problems, that incrementally builds candidates to the solutions,
and abandons a candidate ("backtracks") as soon as it determines that the candidate cannot
possibly be completed to a valid solution.[1]

The classic textbook example of the use of backtracking is the eight queens puzzle, that asks
for all arrangements of eight chess queens on a standard chessboard so that no queen attacks
any other. In the common backtracking approach, the partial candidates are arrangements
of k queens in the first k rows of the board, all in different rows and columns. Any partial
solution that contains two mutually attacking queens can be abandoned.

Backtracking can be applied only for problems which admit the concept of a "partial
candidate solution" and a relatively quick test of whether it can possibly be completed to a
valid solution. It is useless, for example, for locating a given value in an unordered table.
When it is applicable, however, backtracking is often much faster than brute-force
enumeration of all complete candidates, since it can eliminate many candidates with a single
test.

Backtracking is an important tool for solving constraint satisfaction problems,[2] such


as crosswords, verbal arithmetic, Sudoku, and many other puzzles. It is often the most
convenient technique for parsing,[3] for the knapsack problem and other combinatorial
optimization problems. It is also the program execution strategy used in the programming
languages Icon, Planner and Prolog.

ALGORITHM OF BACK TRACKING

Backtrack(s)

ifs is not a solution

return false

if is a new solution

add to list of solutions

backtrack (expand s)

It finds a solution by building a solution step by step, increasing levels over time,
using recursive calling. A search tree known as the state-space tree is used to find these
solutions. Each branch in a state-space tree represents a variable, and each level represents a
solution.

A backtracking algorithm uses the depth-first search method. When the algorithm begins to
explore the solutions, the abounding function is applied so that the algorithm can determine
whether the proposed solution satisfies the constraints. If it does, it will keep looking. If it
does not, the branch is removed, and the algorithm returns to the previous level.

State-Space Tree

A space state tree is a tree that represents all of the possible states of the problem, from the
root as an initial state to the leaf as a terminal state.

How Does a Backtracking Algorithm Work?

In any backtracking algorithm, the algorithm seeks a path to a feasible solution that includes
some intermediate checkpoints. If the checkpoints do not lead to a viable solution, the
problem can return to the checkpoints and take another path to find a solution. Consider the
following scenario:
In this case, S represents the problem's starting point. You start at S and work your way to
solution S1 via the midway point M1. However, you discovered that solution S1 is not a
viable solution to our problem. As a result, you backtrack (return) from S1, return to M1,
return to S, and then look for the feasible solution S2. This process is repeated until you
arrive at a workable solution.

S1 and S2 are not viable options in this case. According to this example, only S3 is a viable
solution. When you look at this example, you can see that we go through all possible
combinations until you find a viable solution. As a result, you refer to backtracking as a
brute-force algorithmic technique.

A "space state tree" is the above tree representation of a problem. It represents all possible
states of a given problem (solution or non-solution).

The final algorithm is as follows:

• Step 1: Return success if the current point is a viable solution.

• Step 2: Otherwise, if all paths have been exhausted (i.e., the current point is an
endpoint), return failure because there is no feasible solution.

• Step 3: If the current point is not an endpoint, backtrack and explore other points,
then repeat the preceding steps.
An Example of Backtracking Algorithm

Now, this tutorial is going to use a straightforward example to explain the theory behind the
backtracking process. You need to arrange the three letters x, y, and z so that z cannot be next
to x.

According to the backtracking, you will first construct a state-space tree. Look for all possible
solutions and compare them to the given constraint. You must only keep solutions that meet
the following constraint:

The following are possible solutions to the problems: (x,y,z), (x,z,y), (y,x,z), (y,z,x), (z,x,y)
(z,y,x).

Nonetheless, valid solutions to this problem are those that satisfy the constraint that keeps
only (x,y,z) and (z,y,x) in the final solution set.

Types of Backtracking Algorithm

Backtracking algorithms are classified into two types:

1. Algorithm for recursive backtracking

2. Non-recursive backtracking algorithm


1.Recursive backtracking algorithm - Backtracking uses recursion to solve it's problems. It
does so by exploring all the possiblities of any problem, unless it finds the best and feasible
solution to it. Recursion occurs when a function calls itself repeatedly to split a problem into
smaller sub-problems, until it reaches the base case.

2. Non- recursive backtracking algorithm - A non-recursive backtracking algorithm is an


algorithm that uses an iterative approach, typically involving a loop and an explicit data
structure such as a stack, to manage the backtracking process. This is in contrast to the
recursive backtracking algorithm, which uses function calls and the call stack to maintain the
state and control the backtracking.

RECURSIVE BACK TRACKING ALGORITHM

A recursive backtracking algorithm is a type of algorithm that solves problems by recursively


exploring potential solutions and backtracking when necessary. The basic idea is to make
choices at each step, explore the consequences of those choices, and undo them if they do not
lead to a valid solution. The recursive nature of the algorithm is often well-suited for
problems that can be naturally decomposed into subproblems.

Algorithm for Recursive Backtracking

Backtracking must be described in this manner because it is a postorder traversal of a tree:

1. Algorithm Backtrack (s)

2. // Using recursion, this scheme describes the backtracking process.

3. //The first s-1 values are entered.

4. // z [1], z [2]… z [s-1] of the solution vector.

5. // z [1:n] have been assigned. Z [] and n are global.

6. {
7. For (each z [s] £ T (z [1],……,z [s-1]) do

8. {

9. If ( Bk (z [1], z[2],……….,z [s] != 0) then10 {

11. If (z[1], z[2], …… , z[s] is a path to an answer node )

12. Then write (z[1:s]);

13. If(s<n) then backtrack (s+1);

14. }

15. }

16. }

The solution vectors (z1, z2, zs) are regarded as a global array z [1: n]. All of the possible
elements for the zth position of the tuple that satisfy Bs are generated one at a time and then
adjoined to the current vector (z1... zs-1). When zs is attached, a check is made to see if a
solution has been found. When the for loop on line 7 is finished, there are no more values for
zs, and the current copy of the backtrack ends.

EXAMPLE FOR RECURSIVE BACK TRACKING ALGORITHM

01) Rat in a Maze

Problem Statement: You are given a matrix of order N*N having 1's and 0's written as its
elements. Now, imagine that there is a rat at (0,0) and he needs to reach the destination at (N-
1, N-1). You need to provide the paths for the rat to reach the destination. Now, 1 means that
you can go through the element but 0 means that you cannot. Also, you need to take care of
the fact that you can either go up(U), down(D), left(L), or right(R). Print the possible paths.

Input: N=4; m[][]={{1,0,0,0}, {1,1,0,1}, {1,1,0,0}, {0,1,1,1}}

Output: DDRDRR, DRDDRR


Explanation: Take a look at the below illustration to understand the solution more precisely.
Now, you start from (0,0) and see that there is a 1 down. So, you take that path and then
move again down as again 1 is present. Now you take a right which is followed by a down
and later twice right turns, thus finally reaching the destination. In the same way, you can
take another path

//C++ Program for Rat In A Maze Problem

#include<Stdio.h>
using namespace std;
bool isSafe(int x,int y,int n,int m,vector<vector<int>> &maze,vector<vector<int>> visited){
//Checking our next move is safe by checking if it is present in boundries of maze and not
visited and
//value of next position should be 1
if((x>=0 && x<n) && (y>=0 && y<m) && visited[x][y] == 0 && maze[x][y] == 1){
return true;
}
else{
return false;
}
}

void solve(vector<vector<int>> &maze, int n,int m,int x,int y,string path, vector<string>&
ans,
vector<vector<int>> visited){

//If reach the destination store path in ans and return


if(x==n-1 && y==m-1){
ans.push_back(path);
return;
}

//Mark visited where rat is present


visited[x][y]=1;

//4 directions D/L/R/U where rat can travel

//Down
int newx=x+1;
int newy=y;
//Checking if it is safe to go down
if(isSafe(newx,newy,n,m,maze,visited)){
//Inserting next direction of rat in path
path.push_back('D');
//Function Call
solve(maze,n,m,newx,newy,path,ans,visited);
//backtracking
path.pop_back();
}

//UP
newx=x-1;
newy=y;
//Checking if it is safe to go UP
if(isSafe(newx,newy,n,m,maze,visited)){
//Inserting next direction of rat in path
path.push_back('U');
//Function Call
solve(maze,n,m,newx,newy,path,ans,visited);
//backtracking
path.pop_back();
}

//Left
newx=x;
newy=y-1;
//Checking if it is safe to go left
if(isSafe(newx,newy,n,m,maze,visited)){
//Inserting next direction of rat in path
path.push_back('L');
//Function Call
solve(maze,n,m,newx,newy,path,ans,visited);
//backtracking
path.pop_back();
}
//right
newx=x;
newy=y+1;
//Checking if it is safe to go right
if(isSafe(newx,newy,n,m,maze,visited)){
//Inserting next direction of rat in path
path.push_back('R');
//Function Call
solve(maze,n,m,newx,newy,path,ans,visited);
//backtracking
path.pop_back();
}

//marking vis false as we return


visited[x][y] = 0;
}

vector<string> possiblePaths(vector<vector<int>> &maze) {


//Size of the maze
int n = maze.size();
int m = maze[0].size();
vector<string> ans; //Storing all the paths in ans vector
//if starting and end postion value is 0 then we can't have any path
if(maze[0][0] == 0 || maze[n-1][m-1]==0){
return ans;
}
//Starting Position of rat
int x =0;
int y =0;
//Storing the positions where rat is visited
vector<vector<int>> visited(n,vector<int>(m,0));

string path = ""; //For storing the path at a time


//Function Call
solve(maze,n,m,x,y,path,ans,visited);

//Return sorted paths


sort(ans.begin(),ans.end());

return ans;
}\
//right
newx=x;
newy=y+1;
//Checking if it is safe to go right
if(isSafe(newx,newy,n,m,maze,visited)){
//Inserting next direction of rat in path
path.push_back('R');
//Function Call
solve(maze,n,m,newx,newy,path,ans,visited);
//backtracking
path.pop_back();
}

//marking vis false as we return


visited[x][y] = 0;
}

vector<string> possiblePaths(vector<vector<int>> &maze) {


//Size of the maze
int n = maze.size();
int m = maze[0].size();
vector<string> ans; //Storing all the paths in ans vector
//if starting and end postion value is 0 then we can't have any path
if(maze[0][0] == 0 || maze[n-1][m-1]==0){
return ans;
}
//Starting Position of rat
int x =0;
int y =0;
//Storing the positions where rat is visited
vector<vector<int>> visited(n,vector<int>(m,0));

string path = ""; //For storing the path at a time


//Function Call
solve(maze,n,m,x,y,path,ans,visited);

//Return sorted paths


sort(ans.begin(),ans.end());

return ans;
}
Output:
DDRDRR, DRDDRR

02) Sudoku Solver

Problem Statement: You are given a Sudoku grid with some empty cells. You need to write a
code such that all the cells are filled in a proper fashion according to Sudoku rules which are:

Each of the digits 1-9 must occur exactly once in each row.

Each of the digits 1-9 must occur exactly once in each column.

Each of the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Input:

{{'5','3','.','.','7','.','.','.','.'},

{'6','.','.','1','9','5','.','.','.'},

{'.','9','8','.','.','.','.','6','.'},

{'8','.','.','.','6','.','.','.','3'},

{'4','.','.','8','.','3','.','.','1'},

{'7','.','.','.','2','.','.','.','6'},

{'.','6','.','.','.','.','2','8','.'},

{'.','.','.','4','1','9','.','.','5'},

{'.','.','.','.','8','.','.','7','9'}}

Output:
{{5, 3, 4, 6, 7, 8, 9, 1, 2},

{6, 7, 2, 1, 9, 5, 3, 4, 8},

{1, 9, 8, 3, 4, 2, 5, 6, 7},

{8, 5, 9, 7, 6, 1, 4, 2, 3},

{4, 2, 6, 8, 5, 3, 7, 9, 1},

{7, 1, 3, 9, 2, 4, 8, 5, 6},

{9, 6, 1, 5, 3, 7, 2, 8, 4},

{2, 8, 7, 4, 1, 9, 6, 3, 5},

{3, 4, 5, 2, 8, 6, 1, 7, 9}}

Explanation:
In this example, there is nothing much to explain. Since it is a simple Sudoku solver code that
solves the provided matrix as sudoku. You can take a look at the below picture to understand
the solution.

//C++ Program For Sudoku Solver Problem

#include<stdio.h>
using namespace std;
bool isSafe(int row,int col,char val,vector<vector<char>>& board){
//Checking if the val is not present at it's row,col and 3x3 box
for(int i=0;i<board.size();i++){
//For checking it's row
if(board[row][i]==val) return false;

//For Checking it's col


if(board[i][col]==val) return false;

//For checking it's 3x3 box


if(board[3*(row/3) + i/3][3*(col/3)+ i%3]==val) return false;
}

//If we didn't find val at it's row,col and 3x3 box then return true
return true;

}
bool sudokuSolver(vector<vector<char>>& board){
//Iterating through board from start to end
for(int i=0;i<board.size();i++){
for(int j=0;j<board[i].size();j++){
//If we find empty column
if(board[i][j]=='.'){
//Check from 1 to 9 value for i,j board
for(int k=1;k<=9;k++){
//Check the kth value is safe for the sudoku to complete
char num = k+'0';
if(isSafe(i,j,num,board)){
//if it is safe then give the value to that column
//And make recursive call for checking sudoku can be solved with that value
board[i][j]=num;
//Recursive Call
bool check = sudokuSolver(board);
//If possible then return true and our board will contain our ans
if(check){
return true;
}
else{
// Else do Backtrack
board[i][j]='.';
}
}
}
//If we didn't find any ans for i,j column then return false;
return false;
}
}
}
//return true after iterating through whole board as we didn't find any empty column
return true;
}

int main() {
//Initializing the sudoku As a 2d vector board
vector<vector<char>> board = {{'5','3','.','.','7','.','.','.','.'},
{'6','.','.','1','9','5','.','.','.'},{'.','9','8','.','.','.','.','6','.'},
{'8','.','.','.','6','.','.','.','3'},{'4','.','.','8','.','3','.','.','1'},{'7','.','.','.','2','.','.','.','6'},{'.','6','.','.','.','.','2','8','.'
},{'.','.','.','4','1','9','.','.','5'},{'.','.','.','.','8','.','.','7','9'}};
int n = board.size();
//Function Call For finding Solution of Sudoku
bool findSudoku = sudokuSolver(board);
//If we can't find find solution of sudoku then
if(findSudoku == false) cout<<"Not A Valid Sudoku";
else{
//if we find the solution then print
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cout<<board[i][j]<<" ";
}
cout<<endl;
}
}

return 0;
}
Output:
534678912
672195348
198342567
859761423
426853791
713924856
961537284
287419635
345286179

NON-RECURSIVE BACKTRACKING ALGORITHM

In a non-recursive algorithm, an iterative or non-recursive version of the recursive algorithm


appears.

1. Backtracking Algorithm(s)

2. This scheme describes the process of backtracking.

3. // all solutions in z [1: n] are generated and printed

3. / all solutions in z [1: n] are generated and printed

5.{

6.s=1;
7. While (s!= 0) do

8.{

9.If ( there remains are untried z [1] £ X ( z [1], z [2], ….., z [s-1]) and Bk (z[1], ….., z[s]) is
true) then

10. {

11. If ( z[1], …., z[s] is a path to an answer node)

12. Then write ( z[1 : s]);

13. S = s + 1

14. }

15. Else s=s - 1 // backtrack the previous set

16.}

17.}

X() returns the set of all possible values assigned to the solution vector's first component, z1.
The component z1 will accept values that satisfy the bounding function B1 (z1). As you
progress through this tutorial, you will see some of the applications of the backtracking.

EXAMPLE FOR NON-RECURSIVE BACKTRACKING ALGORITHM

03) N-Queens Problem

Problem Statement: You are given a chessboard of order n*n and n queens. Now, you have to
place the queens in such a position that no queen can attack each other. As per the Chess
rules, a Queen can move in any direction that is, forward, backward, left, right, and
diagonally. So, you will return the number of possible positions such that the queens can be
placed.

Input: n=4
Output: [[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]

*The '.' represent the empty spaces.

Explanation: We start by putting the queens one by one on the chessboard. If at any time, a
queen cannot be placed, we change the other queens' location and reorganize them using
backtracking. Look at the below illustration to understand.

#include <iostream>
#include <vector>
#include <stack>

bool isSafe(const std::vector<int>& board, int row, int col) {


for (int i = 0; i < row; ++i) {
if (board[i] == col || board[i] - i == col - row || board[i] + i == col + row) {
return false; // Check if placing a queen in the current position violates constraints
}
}
return true;
}

void solveNQueens(int N) {
std::vector<int> board(N, -1); // Initialize the board with -1 indicating no queen is placed
std::stack<std::pair<int, int>> stack; // Stack to store the state (row, col)

int col = 0;
int row = 0;
while (row < N || !stack.empty()) {
if (row == N) {
// All queens are placed successfully
// Print the solution or process it as needed
for (int i = 0; i < N; ++i) {
std::cout << board[i] << " ";
}
std::cout << "\n";

// Backtrack to find the next solution


--row;
col = board[row] + 1;
stack.pop();
} else {
while (col < N) {
if (isSafe(board, row, col)) {
// Place queen and move to the next row
board[row] = col;
stack.push({row, col});
++row;
col = 0;
break;
}
++col;
}

if (col == N) {
// If no safe place is found, backtrack
if (!stack.empty()) {
auto [prevRow, prevCol] = stack.top();
stack.pop();
board[prevRow] = -1;
row = prevRow;
col = prevCol + 1;
} else {
break; // No more solutions
}
}
}
}
}

int main() {
int N = 8; // Change N to the desired size of the chessboard
solveNQueens(N);

return 0;
}
Output:
The distinct solution of N Queen Puzzle are :
[.Q.. ...Q Q... ..Q. ] [..Q. Q... ...Q .Q.. ]

04) Array Permutations


Problem Statement: You are given an array with certain elements. You need to return an
array that consists of all the possible permutations of the elements present in the inputted
array. Permutation refers to the arrangement of objects.

Input: {1,2,3,4}

Output: Permutations of {1,2,3,4} are :

{[1234],[1243],[1324],[1342],[1432],[1423],[2134],[2143]
,[2314],[2341],[2431],[2413],[3214],[3241],[3124],[3142],
[ 3 4 1 2 ] , [ 3 4 2 1 ] , [ 4 2 3 1 ] , [ 4 2 1 3 ] , [ 4 3 2 1 ] , [ 4 3 1 2 ] , [ 4 1 3 2 ] , [ 4 1 2 3 ]}

Explanation: We didn't do anything except the steps that have already been mentioned
above.

#include <iostream>
#include <vector>
#include <stack>

void generatePermutations(const std::vector<int>& elements) {


int n = elements.size();
std::vector<int> current(n, 0); // To store the current permutation
std::vector<bool> used(n, false); // To track used elements
std::stack<int> stack; // To store the state of the algorithm

int index = 0;

while (index >= 0) {


// Choose: Find the next unused element
int i;
for (i = current[index]; i < n; ++i) {
if (!used[i]) {
current[index] = i; // Make a choice
used[i] = true;
stack.push(index); // Save the current state on the stack
++index;
break;
}
}

if (i == n) {
// If no unused element is found, backtrack
if (index > 0) {
--index;
used[current[index]] = false;
}
} else if (index == n) {
// If a complete permutation is formed, print it
for (int num : current) {
std::cout << elements[num] << " ";
}
std::cout << std::endl;
}
}
}

int main() {
std::vector<int> elements = {1, 2, 3};
generatePermutations(elements);

return 0;
}

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy