N Queen Problem using Branch And Bound
The N queens puzzle is the problem of placing N chess queens on an N×N chessboard so that no two queens threaten each other. Thus, a solution requires that no two queens share the same row, column, or diagonal.
The backtracking Algorithm for N-Queen is already discussed here. In a backtracking solution, we backtrack when we hit a dead end. In Branch and Bound solution, after building a partial solution, we figure out that there is no point going any deeper as we are going to hit a dead end.
Let’s begin by describing the backtracking solution. “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.”
Placing 1st queen on (3, 0) and 2nd queen on (5, 1)
- For the 1st Queen, there are total 8 possibilities as we can place 1st Queen in any row of first column. Let’s place Queen 1 on row 3.
- After placing 1st Queen, there are 7 possibilities left for the 2nd Queen. But wait, we don’t really have 7 possibilities. We cannot place Queen 2 on rows 2, 3 or 4 as those cells are under attack from Queen 1. So, Queen 2 has only 8 – 3 = 5 valid positions left.
- After picking a position for Queen 2, Queen 3 has even fewer options as most of the cells in its column are under attack from the first 2 Queens.
We need to figure out an efficient way of keeping track of which cells are under attack. In previous solution we kept an 8-by-8 Boolean matrix and update it each time we placed a queen, but that required linear time to update as we need to check for safe cells.
Basically, we have to ensure 4 things:
1. No two queens share a column.
2. No two queens share a row.
3. No two queens share a top-right to left-bottom diagonal.
4. No two queens share a top-left to bottom-right diagonal.
Number 1 is automatic because of the way we store the solution. For number 2, 3 and 4, we can perform updates in O(1) time. The idea is to keep three Boolean arrays that tell us which rows and which diagonals are occupied.
Lets do some pre-processing first. Let’s create two N x N matrix one for / diagonal and other one for \ diagonal. Let’s call them slashCode and backslashCode respectively. The trick is to fill them in such a way that two queens sharing a same /diagonal will have the same value in matrix slashCode, and if they share same \diagonal, they will have the same value in backslashCode matrix.
For an N x N matrix, fill slashCode and backslashCode matrix using below formula –
slashCode[row][col] = row + col
backslashCode[row][col] = row – col + (N-1)
Using above formula will result in below matrices
The ‘N – 1’ in the backslash code is there to ensure that the codes are never negative because we will be using the codes as indices in an array.
Now before we place queen i on row j, we first check whether row j is used (use an array to store row info). Then we check whether slash code ( j + i ) or backslash code ( j – i + 7 ) are used (keep two arrays that will tell us which diagonals are occupied). If yes, then we have to try a different location for queen i. If not, then we mark the row and the two diagonals as used and recurse on queen i + 1. After the recursive call returns and before we try another position for queen i, we need to reset the row, slash code and backslash code as unused again, like in the code from the previous notes.
Below is the implementation of above idea –
This code Takes the Dynamic Input:
C++
#include<bits/stdc++.h>
using namespace std;
int N;
void printSol(vector<vector< int >>board)
{
for ( int i = 0;i<N;i++){
for ( int j = 0;j<N;j++){
cout<<board[i][j]<< " " ;
}
cout<< "\n" ;
}
}
bool isSafe( int row , int col ,vector< bool >rows , vector< bool >left_digonals ,vector< bool >Right_digonals)
{
if (rows[row] == true || left_digonals[row+col] == true || Right_digonals[col-row+N-1] == true ){
return false ;
}
return true ;
}
bool solve(vector<vector< int >>& board , int col ,vector< bool >rows , vector< bool >left_digonals ,vector< bool >Right_digonals)
{
if (col>=N){
return true ;
}
for ( int i = 0;i<N;i++)
{
if (isSafe(i,col,rows,left_digonals,Right_digonals) == true )
{
rows[i] = true ;
left_digonals[i+col] = true ;
Right_digonals[col-i+N-1] = true ;
board[i][col] = 1;
if (solve(board,col+1,rows,left_digonals,Right_digonals) == true ){
return true ;
}
rows[i] = false ;
left_digonals[i+col] = false ;
Right_digonals[col-i+N-1] = false ;
board[i][col] = 0;
}
}
return false ;
}
int main()
{
cout<< "Enter the no of rows for the square Board : " ;
cin>>N;
vector<vector< int >>board(N,vector< int >(N,0));
vector< bool >rows(N, false );
vector< bool >left_digonals(2*N-1, false );
vector< bool >Right_digonals(2*N-1, false );
bool ans = solve(board , 0, rows,left_digonals,Right_digonals);
if (ans == true ){
printSol(board);
}
else {
cout<< "Solution Does not Exist\n" ;
}
}
|
C
#include<stdio.h>
#include<string.h>
#include<stdbool.h>
#define N 8
void printSolution( int board[N][N])
{
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < N; j++)
printf ( "%2d " , board[i][j]);
printf ( "\n" );
}
}
bool isSafe( int row, int col, int slashCode[N][N],
int backslashCode[N][N], bool rowLookup[],
bool slashCodeLookup[], bool backslashCodeLookup[] )
{
if (slashCodeLookup[slashCode[row][col]] ||
backslashCodeLookup[backslashCode[row][col]] ||
rowLookup[row])
return false ;
return true ;
}
bool solveNQueensUtil( int board[N][N], int col,
int slashCode[N][N], int backslashCode[N][N],
bool rowLookup[N],
bool slashCodeLookup[],
bool backslashCodeLookup[] )
{
if (col >= N)
return true ;
for ( int i = 0; i < N; i++)
{
if ( isSafe(i, col, slashCode,
backslashCode, rowLookup,
slashCodeLookup, backslashCodeLookup) )
{
board[i][col] = 1;
rowLookup[i] = true ;
slashCodeLookup[slashCode[i][col]] = true ;
backslashCodeLookup[backslashCode[i][col]] = true ;
if ( solveNQueensUtil(board, col + 1,
slashCode, backslashCode,
rowLookup, slashCodeLookup, backslashCodeLookup) )
return true ;
board[i][col] = 0;
rowLookup[i] = false ;
slashCodeLookup[slashCode[i][col]] = false ;
backslashCodeLookup[backslashCode[i][col]] = false ;
}
}
return false ;
}
bool solveNQueens()
{
int board[N][N];
memset (board, 0, sizeof board);
int slashCode[N][N];
int backslashCode[N][N];
bool rowLookup[N] = { false };
bool slashCodeLookup[2*N - 1] = { false };
bool backslashCodeLookup[2*N - 1] = { false };
for ( int r = 0; r < N; r++)
for ( int c = 0; c < N; c++) {
slashCode[r] = r + c,
backslashCode[r] = r - c + 7;
}
if (solveNQueensUtil(board, 0,
slashCode, backslashCode,
rowLookup, slashCodeLookup, backslashCodeLookup) ==
false )
{
printf ( "Solution does not exist" );
return false ;
}
printSolution(board);
return true ;
}
int main()
{
solveNQueens();
return 0;
}
|
Java
import java.io.*;
import java.util.Arrays;
class GFG{
static int N = 8 ;
static void printSolution( int board[][])
{
int N = board.length;
for ( int i = 0 ; i < N; i++)
{
for ( int j = 0 ; j < N; j++)
System.out.printf( "%2d " , board[i][j]);
System.out.printf( "\n" );
}
}
static boolean isSafe( int row, int col,
int slashCode[][],
int backslashCode[][],
boolean rowLookup[],
boolean slashCodeLookup[],
boolean backslashCodeLookup[])
{
if (slashCodeLookup[slashCode[row][col]] ||
backslashCodeLookup[backslashCode[row][col]] ||
rowLookup[row])
return false ;
return true ;
}
static boolean solveNQueensUtil(
int board[][], int col, int slashCode[][],
int backslashCode[][], boolean rowLookup[],
boolean slashCodeLookup[],
boolean backslashCodeLookup[])
{
int N = board.length;
if (col >= N)
return true ;
for ( int i = 0 ; i < N; i++)
{
if (isSafe(i, col, slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup))
{
board[i][col] = 1 ;
rowLookup[i] = true ;
slashCodeLookup[slashCode[i][col]] = true ;
backslashCodeLookup[backslashCode[i][col]] = true ;
if (solveNQueensUtil(
board, col + 1 , slashCode,
backslashCode, rowLookup,
slashCodeLookup,
backslashCodeLookup))
return true ;
board[i][col] = 0 ;
rowLookup[i] = false ;
slashCodeLookup[slashCode[i][col]] = false ;
backslashCodeLookup[backslashCode[i][col]] = false ;
}
}
return false ;
}
static boolean solveNQueens()
{
int board[][] = new int [N][N];
int slashCode[][] = new int [N][N];
int backslashCode[][] = new int [N][N];
boolean [] rowLookup = new boolean [N];
boolean slashCodeLookup[] = new boolean [ 2 * N - 1 ];
boolean backslashCodeLookup[] = new boolean [ 2 * N - 1 ];
for ( int r = 0 ; r < N; r++)
for ( int c = 0 ; c < N; c++)
{
slashCode[r] = r + c;
backslashCode[r] = r - c + 7 ;
}
if (solveNQueensUtil(board, 0 , slashCode,
backslashCode, rowLookup,
slashCodeLookup,
backslashCodeLookup) == false )
{
System.out.printf( "Solution does not exist" );
return false ;
}
printSolution(board);
return true ;
}
public static void main(String[] args)
{
solveNQueens();
}
}
|
Python3
N = 8
def printSolution(board):
for i in range (N):
for j in range (N):
print (board[i][j], end = " " )
print ()
def isSafe(row, col, slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup):
if (slashCodeLookup[slashCode[row][col]] or
backslashCodeLookup[backslashCode[row][col]] or
rowLookup[row]):
return False
return True
def solveNQueensUtil(board, col, slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup):
if (col > = N):
return True
for i in range (N):
if (isSafe(i, col, slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup)):
board[i][col] = 1
rowLookup[i] = True
slashCodeLookup[slashCode[i][col]] = True
backslashCodeLookup[backslashCode[i][col]] = True
if (solveNQueensUtil(board, col + 1 ,
slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup)):
return True
board[i][col] = 0
rowLookup[i] = False
slashCodeLookup[slashCode[i][col]] = False
backslashCodeLookup[backslashCode[i][col]] = False
return False
def solveNQueens():
board = [[ 0 for i in range (N)]
for j in range (N)]
slashCode = [[ 0 for i in range (N)]
for j in range (N)]
backslashCode = [[ 0 for i in range (N)]
for j in range (N)]
rowLookup = [ False ] * N
x = 2 * N - 1
slashCodeLookup = [ False ] * x
backslashCodeLookup = [ False ] * x
for rr in range (N):
for cc in range (N):
slashCode[rr][cc] = rr + cc
backslashCode[rr][cc] = rr - cc + 7
if (solveNQueensUtil(board, 0 , slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup) = = False ):
print ( "Solution does not exist" )
return False
printSolution(board)
return True
solveNQueens()
|
C#
using System;
using System.Linq;
class GFG {
static int N = 8;
static void printSolution( int [, ] board)
{
for ( int i = 0; i < N; i++) {
for ( int j = 0; j < N; j++)
Console.Write( "{0} " , board[i, j]);
Console.WriteLine();
}
}
static bool isSafe( int row, int col, int [, ] slashCode,
int [, ] backslashCode,
bool [] rowLookup,
bool [] slashCodeLookup,
bool [] backslashCodeLookup)
{
if (slashCodeLookup[slashCode[row, col]]
|| backslashCodeLookup[backslashCode[row, col]]
|| rowLookup[row])
return false ;
return true ;
}
static bool solveNQueensUtil( int [, ] board, int col,
int [, ] slashCode,
int [, ] backslashCode,
bool [] rowLookup,
bool [] slashCodeLookup,
bool [] backslashCodeLookup)
{
if (col >= N)
return true ;
for ( int i = 0; i < N; i++) {
if (isSafe(i, col, slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup)) {
board[i, col] = 1;
rowLookup[i] = true ;
slashCodeLookup[slashCode[i, col]] = true ;
backslashCodeLookup[backslashCode[i, col]]
= true ;
if (solveNQueensUtil(
board, col + 1, slashCode,
backslashCode, rowLookup,
slashCodeLookup,
backslashCodeLookup))
return true ;
board[i, col] = 0;
rowLookup[i] = false ;
slashCodeLookup[slashCode[i, col]] = false ;
backslashCodeLookup[backslashCode[i, col]]
= false ;
}
}
return false ;
}
static bool solveNQueens()
{
int [, ] board = new int [N, N];
int [, ] slashCode = new int [N, N];
int [, ] backslashCode = new int [N, N];
bool [] rowLookup = new bool [N];
bool [] slashCodeLookup = new bool [2 * N - 1];
bool [] backslashCodeLookup = new bool [2 * N - 1];
for ( int r = 0; r < N; r++) {
for ( int c = 0; c < N; c++) {
slashCode[r, c] = r + c;
backslashCode[r, c] = r - c + N - 1;
}
}
if (!solveNQueensUtil(board, 0, slashCode,
backslashCode, rowLookup,
slashCodeLookup,
backslashCodeLookup)) {
Console.WriteLine( "Solution does not exist" );
return false ;
}
printSolution(board);
return true ;
}
public static void Main() { solveNQueens(); }
}
|
Javascript
<script>
let N = 8;
function printSolution(board)
{
let N = board.length;
for (let i = 0; i < N; i++)
{
for (let j = 0; j < N; j++)
document.write(board[i][j]+ " " );
document.write( "<br>" );
}
}
function isSafe(row,col,slashCode,backslashCode,rowLookup,slashCodeLookup,backslashCodeLookup)
{
if (slashCodeLookup[slashCode[row][col]] ||
backslashCodeLookup[backslashCode[row][col]] ||
rowLookup[row])
return false ;
return true ;
}
function solveNQueensUtil(board,col,slashCode,
backslashCode,rowLookup,slashCodeLookup,backslashCodeLookup)
{
if (col >= N)
return true ;
for (let i = 0; i < N; i++)
{
if (isSafe(i, col, slashCode, backslashCode,
rowLookup, slashCodeLookup,
backslashCodeLookup))
{
board[i][col] = 1;
rowLookup[i] = true ;
slashCodeLookup[slashCode[i][col]] = true ;
backslashCodeLookup[backslashCode[i][col]] = true ;
if (solveNQueensUtil(
board, col + 1, slashCode,
backslashCode, rowLookup,
slashCodeLookup,
backslashCodeLookup))
return true ;
board[i][col] = 0;
rowLookup[i] = false ;
slashCodeLookup[slashCode[i][col]] = false ;
backslashCodeLookup[backslashCode[i][col]] = false ;
}
}
return false ;
}
function solveNQueens()
{
let board = new Array(N);
let slashCode = new Array(N);
let backslashCode = new Array(N);
for (let i=0;i<N;i++)
{
board[i]= new Array(N);
slashCode[i]= new Array(N);
backslashCode[i]= new Array(N);
for (let j=0;j<N;j++)
{
board[i][j]=0;
slashCode[i][j]=0;
backslashCode[i][j]=0;
}
}
let rowLookup = new Array(N);
for (let i=0;i<N;i++)
rowLookup[i]= false ;
let slashCodeLookup = new Array(2 * N - 1);
let backslashCodeLookup = new Array(2 * N - 1);
for (let i=0;i<2*N-1;i++)
{
slashCodeLookup[i]= false ;
backslashCodeLookup[i]= false ;
}
for (let r = 0; r < N; r++)
for (let c = 0; c < N; c++)
{
slashCode[r] = r + c;
backslashCode[r] = r - c + 7;
}
if (solveNQueensUtil(board, 0, slashCode,
backslashCode, rowLookup,
slashCodeLookup,
backslashCodeLookup) == false )
{
document.write( "Solution does not exist" );
return false ;
}
printSolution(board);
return true ;
}
solveNQueens();
</script>
|
Input:
Enter the no of rows for the square Board : 8
Output :
1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
The time and space complexity of the N-Queen problem solver implemented in the provided code are:
Time Complexity: The time complexity of the solver algorithm is O(N!), where N is the number of rows and columns in the square board. This is because for each column, the algorithm tries to place a queen in each row and then recursively tries to place the queens in the remaining columns. The number of possible combinations of queen placements in the board is N! since there can be only one queen in each row and each column.
Space Complexity: The space complexity of the solver algorithm is O(N^2), where N is the number of rows and columns in the square board. This is because we are using a 2D vector to represent the board, which takes up N^2 space. Additionally, we are using three boolean arrays to keep track of the occupied rows and diagonals, which take up 2N-1 space each. Therefore, the total space complexity is O(N^2 + 6N – 3), which is equivalent to O(N^2).
Last Updated :
11 Mar, 2024
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...