Given the dimension of a chess board (N x M), determine the minimum number of queens required to cover all the squares of the board. A queen can attack any square along its row, column or diagonals.
Examples:
Input : N = 8, M = 8 Output : 5 Layout : Q X X X X X X X X X Q X X X X X X X X X Q X X X X Q X X X X X X X X X Q X X X X X X X X X X X X X X X X X X X X X X X X X X X X Input : N = 3, M = 5 Output : 2 Layout : Q X X X X X X X X X X X X Q X
This article attempts to solve the problem in a very simple way without much optimization.
- Step 1: Starting from any corner square of the board, find an ‘uncovered’ square (Uncovered square is a square which isn’t attacked by any of the queens already placed). If none found, goto Step 4.
- Step 2: Place a Queen on this square and increment variable ‘count’ by 1.
- Step 3: Repeat step 1.
- Step 4: Now, you’ve got a layout where every square is covered. Therefore, the value of ‘count’ can be the answer. However, you might be able to do better, as there might exist a better layout with lesser number of queens. So, store this ‘count’ as the best value till now and proceed to find a better solution.
- Step 5: Remove the last queen placed and place it in the next ‘uncovered’ cell. Step 6: Proceed recursively and try out all the possible layouts. Finally, the one with the least number of queens is the answer.
Implementation: Dry run the following code for better understanding.
C++
#include <bits/stdc++.h> using namespace std; // The chessboard is represented by a 2D array. bool board[8][8]; // N x M is the dimension of the chess board. const int N = 8, M = 8; // The minimum number of queens required. // Initially, set to MAX_VAL. int minCount = INT_MAX; string layout; // Stores the best layout. // Stores the current layout in 'layout' // variable as String. void storeLayout() { stringstream ss; for ( int i = 0; i < N; i++) { for ( int j = 0; j < M; j++) ss << (board[i][j] ? "Q " : "X " ); ss << "\n" ; } layout = ss.str(); } // Returns 'true' if the square (row, col) is // being attacked by at least one queen. bool isAttacked( int row, int col) { int i, j; // Check the 'col'th column for any queen. for (i = 0; i < N; ++i) if (board[i][col]) return true ; // Check the 'row'th row for any queen. for (j = 0; j < M; ++j) if (board[row][j]) return true ; // Check the diagonals for any queen. for (i = 0; i < min(N, M); ++i) if (row - i >= 0 && col - i >= 0 && board[row - i][col - i]) return true ; else if (row - i >= 0 && col + i < M && board[row - i][col + i]) return true ; else if (row + i < N && col - i >= 0 && board[row + i][col - i]) return true ; else if (row + i < N && col + i < M && board[row + i][col + i]) return true ; // This square is unattacked. Hence return 'false'. return false ; } // Finds minimum count of queens needed and places them. void placeQueen( int countSoFar) { int i, j; if (countSoFar >= minCount) // We've already obtained a solution with lesser or // same number of queens. Hence, no need to proceed. return ; bool flag = false ; while (!flag) { for (i = 0; i < N; ++i) for (j = 0; j < M; ++j) { if (!isAttacked(i, j)) { i = N; flag = true ; break ; } } if (flag) break ; // All squares all covered. Hence, this // is the best solution till now. minCount = countSoFar; storeLayout(); break ; } // Checks if there exists any unattacked cells. for (i = 0; i < N; ++i) for (j = 0; j < M; ++j) { if (!isAttacked(i, j)) { // Square (i, j) is unattacked. // Therefore, place a queen here. board[i][j] = true ; // Increment 'count' and proceed // recursively. placeQueen(countSoFar + 1); // Remove this queen and attempt to // find a better solution. board[i][j] = false ; } } } // Driver code int main() { memset (board, false , sizeof (board)); placeQueen(0); cout << minCount << endl; cout << "\nLayout: \n" << layout; } |
Java
// Java program to find minimum number of queens needed // to cover a given chess board. public class Backtracking { // The chessboard is represented by a 2D array. static boolean [][] board; // N x M is the dimension of the chess board. static int N, M; // The minimum number of queens required. // Initially, set to MAX_VAL. static int minCount = Integer.MAX_VALUE; static String layout; // Stores the best layout. // Driver code public static void main(String[] args) { N = 8 ; M = 8 ; board = new boolean [N][M]; placeQueen( 0 ); System.out.println(minCount); System.out.println( "\nLayout: \n" + layout); } // Finds minimum count of queens needed and places them. static void placeQueen( int countSoFar) { int i, j; if (countSoFar >= minCount) // We've already obtained a solution with lesser // or same number of queens. Hence, no need to // proceed. return ; // Checks if there exists any unattacked cells. findUnattackedCell : { for (i = 0 ; i < N; ++i) for (j = 0 ; j < M; ++j) if (!isAttacked(i, j)) // Square (i, j) is unattacked. break findUnattackedCell; // All squares all covered. Hence, this // is the best solution till now. minCount = countSoFar; storeLayout(); return ; } for (i = 0 ; i < N; ++i) for (j = 0 ; j < M; ++j) { if (!isAttacked(i, j)) { // Square (i, j) is unattacked. // Therefore, place a queen here. board[i][j] = true ; // Increment 'count' and proceed // recursively. placeQueen(countSoFar + 1 ); // Remove this queen and attempt to // find a better solution. board[i][j] = false ; } } } // Returns 'true' if the square (row, col) is // being attacked by at least one queen. static boolean isAttacked( int row, int col) { int i, j; // Check the 'col'th column for any queen. for (i = 0 ; i < N; ++i) if (board[i][col]) return true ; // Check the 'row'th row for any queen. for (j = 0 ; j < M; ++j) if (board[row][j]) return true ; // Check the diagonals for any queen. for (i = 0 ; i < Math.min(N, M); ++i) if (row - i >= 0 && col - i >= 0 && board[row - i][col - i]) return true ; else if (row - i >= 0 && col + i < M && board[row - i][col + i]) return true ; else if (row + i < N && col - i >= 0 && board[row + i][col - i]) return true ; else if (row + i < N && col + i < M && board[row + i][col + i]) return true ; // This square is unattacked. Hence return 'false'. return false ; } // Stores the current layout in 'layout' // variable as String. static void storeLayout() { StringBuilder sb = new StringBuilder(); for ( boolean [] row : board) { for ( boolean cell : row) sb.append(cell ? "Q " : "X " ); sb.append( "\n" ); } layout = sb.toString(); } } |
C#
using System; using System.Text; class Program { // The chessboard is represented by a 2D array static bool [, ] board = new bool [8, 8]; // N * M is the dimension of the chess board const int N = 8, M = 8; // The minimum number of queens required. // Initially, set to MAX_VALUE. static int minCount = int .MaxValue; // Stores the best layout. static string layout; // Stores the current layout in 'layout' // variable as String. static void StoreLayout() { StringBuilder sb = new StringBuilder(); for ( int i = 0; i < N; i++) { for ( int j = 0; j < M; j++) { sb.Append(board[i, j] ? "Q " : "X " ); } sb.Append( "\n" ); } layout = sb.ToString(); } // Returns 'true' if the square (row, col) is // being attacked by at least one queen. static bool IsAttacked( int row, int col) { int i, j; // Check the 'col'th column for any queen. for (i = 0; i < N; ++i) { if (board[i, col]) return true ; } // Check the 'row'th row for any queen. for (j = 0; j < M; ++j) { if (board[row, j]) return true ; } // Check the diagonals for any queen. for (i = 0; i < Math.Min(N, M); ++i) { if (row - i >= 0 && col - i >= 0 && board[row - i, col - i]) return true ; else if (row - i >= 0 && col + i < M && board[row - i, col + i]) return true ; else if (row + i < N && col - i >= 0 && board[row + i, col - i]) return true ; else if (row + i < N && col + i < M && board[row + i, col + i]) return true ; } // This square is unattacked. Hence return 'false'. return false ; } // Finds minimum count of queens needed and places them. static void PlaceQueen( int countSoFar) { int i, j; // We've already obtained a solution with lesser or // same number of queens. Hence, no need to proceed. if (countSoFar >= minCount) return ; bool flag = false ; while (!flag) { for (i = 0; i < N; ++i) { for (j = 0; j < M; ++j) { if (!IsAttacked(i, j)) { i = N; flag = true ; break ; } } if (flag) break ; } if (flag) break ; // All squares all covered. Hence, this // is the best solution till now. minCount = countSoFar; StoreLayout(); break ; } // Checks if there exists any unattacked cells. for (i = 0; i < N; ++i) { for (j = 0; j < M; ++j) { if (!IsAttacked(i, j)) { // Square (i, j) is unattacked. // Therefore, place a queen here. board[i, j] = true ; // Increment 'count' and proceed // recursively. PlaceQueen(countSoFar + 1); // Remove this queen and attempt to // find a better solution. board[i, j] = false ; } } } } static void Main() { Array.Clear(board, 0, board.Length); PlaceQueen(0); Console.WriteLine(minCount); Console.WriteLine( "\nLayout: \n" + layout); } } |
Javascript
// The chessboard is represented by a 2D array. const board = Array.from(Array(8), () => new Array(8).fill( false )); // N x M is the dimension of the chess board. const N = 8, M = 8; // The minimum number of queens required. // Initially, set to MAX_VALUE. let minCount = Number.MAX_VALUE; let layout = "" ; // Stores the best layout. // Stores the current layout in 'layout' // variable as String. function storeLayout() { let str = "" ; for (let i = 0; i < N; i++) { for (let j = 0; j < M; j++) { if (board[i][j]) { str += "Q " ; } else { str += "X " ; } } str += "\n" ; } layout = str; } // Returns 'true' if the square (row, col) is // being attacked by at least one queen. function isAttacked(row, col) { let i, j; // Check the 'col'th column for any queen. for (i = 0; i < N; ++i) { if (board[i][col]) { return true ; } } // Check the 'row'th row for any queen. for (j = 0; j < M; ++j) { if (board[row][j]) { return true ; } } // Check the diagonals for any queen. for (i = 0; i < Math.min(N, M); ++i) { if ( row - i >= 0 && col - i >= 0 && board[row - i][col - i]) { return true ; } else if ( row - i >= 0 && col + i < M && board[row - i][col + i] ) { return true ; } else if ( row + i < N && col - i >= 0 && board[row + i][col - i] ) { return true ; } else if ( row + i < N && col + i < M && board[row + i][col + i] ) { return true ; } } // This square is unattacked. Hence return 'false'. return false ; } // Finds minimum count of queens needed and places them. function placeQueen(countSoFar) { let i, j; if (countSoFar >= minCount) { // We've already obtained a solution with lesser or // same number of queens. Hence, no need to proceed. return ; } let flag = false ; while (!flag) { for (i = 0; i < N; ++i) { for (j = 0; j < M; ++j) { if (!isAttacked(i, j)) { i = N; flag = true ; break ; } } if (flag) { break ; } } if (flag) { break ; } // All squares are covered. Hence, this // is the best solution till now. minCount = countSoFar; storeLayout(); break ; } // Checks if there exists any unattacked cells. for (i = 0; i < N; ++i) { for (j = 0; j < M; ++j) { if (!isAttacked(i, j)) { // Square (i, j) is unattacked. // Therefore, place a queen here. board[i][j] = true ; // Increment 'count' and proceed // recursively. placeQueen(countSoFar + 1); // Remove this queen and attempt to // find a better solution. board[i][j] = false ; } } } } // Driver code placeQueen(0); console.log(minCount); console.log( "\nLayout: \n" + layout); |
5 Layout: Q X X X X X X X X X Q X X X X X X X X X Q X X X X Q X X X X X X X X X Q X X X X X X X X X X X X X X X X X X X X X X X X X X X X
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!