Back Tracking Algorithm
Back Tracking Algorithm
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.
Backtrack(s)
return false
if is a new solution
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.
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).
• 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.
6. {
7. For (each z [s] £ T (z [1],……,z [s-1]) do
8. {
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.
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.
#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){
//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();
}
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();
}
return ans;
}
Output:
DDRDRR, DRDDRR
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.
#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;
//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
1. Backtracking Algorithm(s)
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. {
13. S = s + 1
14. }
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.
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.."]]
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>
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";
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.. ]
Input: {1,2,3,4}
{[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>
int index = 0;
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;
}