Introduction

N-Queens is a tricky problem. To solve this problem efficiently, it requires knowing the backtracking algorithm. Basically, the problem is to place N queens on an NxN chessboard. So in this article, we will discuss how to solve the N-Queens problem using a backtracking algorithm.

Problem Statement

Given the number of queens n (more than 3), we need to return all valid possible positions of N queens, so that no queens can attack/clash each other on a chessboard, N x N. For example, for 4 queens (n = 4), there exists two solutions, such that in each chessboard position, no two queens can attack/clash each other, as shown in the figure below. If you consider N = 1, 2 & 3, there is no solution to this problem, hence N has to be greater than or equal to 4.

Solution

The most naive approach to this problem is to create an N x N chessboard and recursively try to place queens on it. If all the queens fit in the board, then it's a valid board. The interesting part of this algorithm is the placement of n queens. Firstly, queens can neither share the same row nor the same column. Then, we will try to avoid placing the queens on a spot that is already being attacked/clashed by the queens placed before. Finally, if we successfully place the n-th queen on the board, then we add the board as one of the solutions. Then comes the role of backtracking. By removing the previous queen, we try a new position for that queen to find a new solution. We can achieve backtracking by a shared object/state which is the chessboard and by a recursive method/function that places or removes queens and updates the chessboard. Here is a code sample for the solution of the N-Queens problem in C#:
  1. using System.Linq;
  2. using System.Collections.Generic;
  3. namespace NQueens
  4. {
  5. class Program
  6. {
  7. static void Main(string[] args)
  8. {
  9. NQueensProblem nQueen = new NQueensProblem(4);
  10. var result = nQueen.Solutions;
  11. //result has 2 solutions.
  12. ///solution 1: ["OQOO",
  13. /// "OOOQ",
  14. /// "QOOO",
  15. /// "OOQO"]
  16. ///solution 2: ["OOQO",
  17. /// "QOOO",
  18. /// "OOOQ",
  19. /// "OQOO"]
  20. }
  21. }
  22. class NQueensProblem
  23. {
  24. public List<List<string>> Solutions = new List<List<string>>();
  25. private List<List<int>> ChessBoard = new List<List<int>>();
  26. private readonly int TotalNumberOfQueens;
  27. public NQueensProblem(int numOfQueens)
  28. {
  29. TotalNumberOfQueens = numOfQueens;
  30. //create board schema
  31. for (int i = 0; i < TotalNumberOfQueens; i++)
  32. {
  33. List<int> row = Enumerable.Repeat(0, TotalNumberOfQueens).ToList();
  34. ChessBoard.Add(row);
  35. }
  36. //start placing queen
  37. TryPlaceQueen();
  38. }
  39. //try place 0th queen by default
  40. void TryPlaceQueen(int nthQueen = 0)
  41. {
  42. //check for out of range
  43. if (TotalNumberOfQueens <= nthQueen)
  44. return;
  45. //iterate over every cell
  46. for (int i = 0; i < TotalNumberOfQueens; i++)
  47. {
  48. //skip when no more queen can be added to this board
  49. if (ChessBoard[nthQueen][i] != 0)
  50. continue;
  51. //place the queen and update board
  52. ChessBoard[nthQueen][i] = -1;
  53. UpdateBoard(nthQueen, i, 1);
  54. //this board is valid when last queen is added to last row
  55. if (nthQueen == TotalNumberOfQueens - 1)
  56. AddBoardToSolutions();
  57. //try again adding more queens
  58. else
  59. TryPlaceQueen(nthQueen + 1);
  60. //remove the queen we just added
  61. ChessBoard[nthQueen][i] = 0;
  62. UpdateBoard(nthQueen, i, -1);
  63. }
  64. }
  65. void UpdateBoard(int i, int j, int value)
  66. {
  67. for (int k = 0; k < i; k++)
  68. ChessBoard[k][j] += value;
  69. //for down
  70. for (int k = i + 1; k < TotalNumberOfQueens; k++)
  71. ChessBoard[k][j] += value;
  72. //for left
  73. for (int k = 0; k < j; k++)
  74. ChessBoard[i][k] += value;
  75. //for Right
  76. for (int k = j + 1; k < TotalNumberOfQueens; k++)
  77. ChessBoard[i][k] += value;
  78. //for up-left
  79. for (int m = i - 1, n = j - 1; m >= 0 && n >= 0; m--, n--)
  80. ChessBoard[m][n] += value;
  81. //for up-right
  82. for (int m = i - 1, n = j + 1; m >= 0 && n < TotalNumberOfQueens; m--, n++)
  83. ChessBoard[m][n] += value;
  84. //for down-left
  85. for (int m = i + 1, n = j - 1; m < TotalNumberOfQueens && n >= 0; m++, n--)
  86. ChessBoard[m][n] += value;
  87. //for down-right
  88. for (int m = i + 1, n = j + 1; m < TotalNumberOfQueens && n < TotalNumberOfQueens; m++, n++)
  89. ChessBoard[m][n] += value;
  90. }
  91. void AddBoardToSolutions()
  92. {
  93. List<string> newBoard = new List<string>();
  94. for (int k = 0; k < TotalNumberOfQueens; k++)
  95. {
  96. string row = string.Empty;
  97. for (int j = 0; j < TotalNumberOfQueens; j++)
  98. row += ChessBoard[k][j] == -1 ? "Q" : "O";
  99. newBoard.Add(row);
  100. }
  101. //add current board as a solution
  102. Solutions.Add(newBoard);
  103. }
  104. }
  105. }